1 /*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package javax.swing;
26
27
28 import java.util.HashSet;
29 import java.util.Hashtable;
30 import java.util.Dictionary;
31 import java.util.Enumeration;
32 import java.util.Locale;
33 import java.util.Vector;
34 import java.util.EventListener;
35 import java.util.Set;
36 import java.util.Map;
37 import java.util.HashMap;
38
39 import java.awt.*;
40 import java.awt.event.*;
41 import java.awt.image.VolatileImage;
42 import java.awt.Graphics2D;
43 import java.awt.peer.LightweightPeer;
44 import java.awt.dnd.DropTarget;
45 import java.awt.font.FontRenderContext;
46 import java.beans.PropertyChangeListener;
47 import java.beans.VetoableChangeListener;
48 import java.beans.VetoableChangeSupport;
49 import java.beans.Transient;
50
51 import java.applet.Applet;
52
53 import java.io.Serializable;
54 import java.io.ObjectOutputStream;
55 import java.io.ObjectInputStream;
56 import java.io.IOException;
57 import java.io.ObjectInputValidation;
58 import java.io.InvalidObjectException;
59
60 import javax.swing.border.*;
61 import javax.swing.event.*;
62 import javax.swing.plaf.*;
63 import static javax.swing.ClientPropertyKey.*;
64 import javax.accessibility.*;
65
66 import sun.swing.SwingUtilities2;
67 import sun.swing.UIClientPropertyKey;
68
69 /**
70 * The base class for all Swing components except top-level containers.
71 * To use a component that inherits from <code>JComponent</code>,
72 * you must place the component in a containment hierarchy
73 * whose root is a top-level Swing container.
74 * Top-level Swing containers --
75 * such as <code>JFrame</code>, <code>JDialog</code>,
76 * and <code>JApplet</code> --
77 * are specialized components
78 * that provide a place for other Swing components to paint themselves.
79 * For an explanation of containment hierarchies, see
80 * <a
81 href="http://java.sun.com/docs/books/tutorial/uiswing/overview/hierarchy.html">Swing Components and the Containment Hierarchy</a>,
82 * a section in <em>The Java Tutorial</em>.
83 *
84 * <p>
85 * The <code>JComponent</code> class provides:
86 * <ul>
87 * <li>The base class for both standard and custom components
88 * that use the Swing architecture.
89 * <li>A "pluggable look and feel" (L&F) that can be specified by the
90 * programmer or (optionally) selected by the user at runtime.
91 * The look and feel for each component is provided by a
92 * <em>UI delegate</em> -- an object that descends from
93 * {@link javax.swing.plaf.ComponentUI}.
94 * See <a
95 * href="http://java.sun.com/docs/books/tutorial/uiswing/misc/plaf.html">How
96 * to Set the Look and Feel</a>
97 * in <em>The Java Tutorial</em>
98 * for more information.
99 * <li>Comprehensive keystroke handling.
100 * See the document <a
101 * href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html">Keyboard
102 * Bindings in Swing</a>,
103 * an article in <em>The Swing Connection</em>,
104 * for more information.
105 * <li>Support for tool tips --
106 * short descriptions that pop up when the cursor lingers
107 * over a component.
108 * See <a
109 * href="http://java.sun.com/docs/books/tutorial/uiswing/components/tooltip.html">How
110 * to Use Tool Tips</a>
111 * in <em>The Java Tutorial</em>
112 * for more information.
113 * <li>Support for accessibility.
114 * <code>JComponent</code> contains all of the methods in the
115 * <code>Accessible</code> interface,
116 * but it doesn't actually implement the interface. That is the
117 * responsibility of the individual classes
118 * that extend <code>JComponent</code>.
119 * <li>Support for component-specific properties.
120 * With the {@link #putClientProperty}
121 * and {@link #getClientProperty} methods,
122 * you can associate name-object pairs
123 * with any object that descends from <code>JComponent</code>.
124 * <li>An infrastructure for painting
125 * that includes double buffering and support for borders.
126 * For more information see <a
127 * href="http://java.sun.com/docs/books/tutorial/uiswing/overview/draw.html">Painting</a> and
128 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/border.html">How
129 * to Use Borders</a>,
130 * both of which are sections in <em>The Java Tutorial</em>.
131 * </ul>
132 * For more information on these subjects, see the
133 * <a href="package-summary.html#package_description">Swing package description</a>
134 * and <em>The Java Tutorial</em> section
135 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/jcomponent.html">The JComponent Class</a>.
136 * <p>
137 * <code>JComponent</code> and its subclasses document default values
138 * for certain properties. For example, <code>JTable</code> documents the
139 * default row height as 16. Each <code>JComponent</code> subclass
140 * that has a <code>ComponentUI</code> will create the
141 * <code>ComponentUI</code> as part of its constructor. In order
142 * to provide a particular look and feel each
143 * <code>ComponentUI</code> may set properties back on the
144 * <code>JComponent</code> that created it. For example, a custom
145 * look and feel may require <code>JTable</code>s to have a row
146 * height of 24. The documented defaults are the value of a property
147 * BEFORE the <code>ComponentUI</code> has been installed. If you
148 * need a specific value for a particular property you should
149 * explicitly set it.
150 * <p>
151 * In release 1.4, the focus subsystem was rearchitected.
152 * For more information, see
153 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
154 * How to Use the Focus Subsystem</a>,
155 * a section in <em>The Java Tutorial</em>.
156 * <p>
157 * <strong>Warning:</strong> Swing is not thread safe. For more
158 * information see <a
159 * href="package-summary.html#threading">Swing's Threading
160 * Policy</a>.
161 * <p>
162 * <strong>Warning:</strong>
163 * Serialized objects of this class will not be compatible with
164 * future Swing releases. The current serialization support is
165 * appropriate for short term storage or RMI between applications running
166 * the same version of Swing. As of 1.4, support for long term storage
167 * of all JavaBeans<sup><font size="-2">TM</font></sup>
168 * has been added to the <code>java.beans</code> package.
169 * Please see {@link java.beans.XMLEncoder}.
170 *
171 * @see KeyStroke
172 * @see Action
173 * @see #setBorder
174 * @see #registerKeyboardAction
175 * @see JOptionPane
176 * @see #setDebugGraphicsOptions
177 * @see #setToolTipText
178 * @see #setAutoscrolls
179 *
180 * @author Hans Muller
181 * @author Arnaud Weber
182 */
183 public abstract class JComponent extends Container implements Serializable,
184 TransferHandler.HasGetTransferHandler
185 {
186 /**
187 * @see #getUIClassID
188 * @see #writeObject
189 */
190 private static final String uiClassID = "ComponentUI";
191
192 /**
193 * @see #readObject
194 */
195 private static final Hashtable<ObjectInputStream, ReadObjectCallback> readObjectCallbacks =
196 new Hashtable<ObjectInputStream, ReadObjectCallback>(1);
197
198 /**
199 * Keys to use for forward focus traversal when the JComponent is
200 * managing focus.
201 */
202 private static Set<KeyStroke> managingFocusForwardTraversalKeys;
203
204 /**
205 * Keys to use for backward focus traversal when the JComponent is
206 * managing focus.
207 */
208 private static Set<KeyStroke> managingFocusBackwardTraversalKeys;
209
210 // Following are the possible return values from getObscuredState.
211 private static final int NOT_OBSCURED = 0;
212 private static final int PARTIALLY_OBSCURED = 1;
213 private static final int COMPLETELY_OBSCURED = 2;
214
215 /**
216 * Set to true when DebugGraphics has been loaded.
217 */
218 static boolean DEBUG_GRAPHICS_LOADED;
219
220 /**
221 * Key used to look up a value from the AppContext to determine the
222 * JComponent the InputVerifier is running for. That is, if
223 * AppContext.get(INPUT_VERIFIER_SOURCE_KEY) returns non-null, it
224 * indicates the EDT is calling into the InputVerifier from the
225 * returned component.
226 */
227 private static final Object INPUT_VERIFIER_SOURCE_KEY =
228 new StringBuilder("InputVerifierSourceKey");
229
230 /* The following fields support set methods for the corresponding
231 * java.awt.Component properties.
232 */
233 private boolean isAlignmentXSet;
234 private float alignmentX;
235 private boolean isAlignmentYSet;
236 private float alignmentY;
237
238 /**
239 * Backing store for JComponent properties and listeners
240 */
241
242 /** The look and feel delegate for this component. */
243 protected transient ComponentUI ui;
244 /** A list of event listeners for this component. */
245 protected EventListenerList listenerList = new EventListenerList();
246
247 private transient ArrayTable clientProperties;
248 private VetoableChangeSupport vetoableChangeSupport;
249 /**
250 * Whether or not autoscroll has been enabled.
251 */
252 private boolean autoscrolls;
253 private Border border;
254 private int flags;
255
256 /* Input verifier for this component */
257 private InputVerifier inputVerifier = null;
258
259 private boolean verifyInputWhenFocusTarget = true;
260
261 /**
262 * Set in <code>_paintImmediately</code>.
263 * Will indicate the child that initiated the painting operation.
264 * If <code>paintingChild</code> is opaque, no need to paint
265 * any child components after <code>paintingChild</code>.
266 * Test used in <code>paintChildren</code>.
267 */
268 transient Component paintingChild;
269
270 /**
271 * Constant used for <code>registerKeyboardAction</code> that
272 * means that the command should be invoked when
273 * the component has the focus.
274 */
275 public static final int WHEN_FOCUSED = 0;
276
277 /**
278 * Constant used for <code>registerKeyboardAction</code> that
279 * means that the command should be invoked when the receiving
280 * component is an ancestor of the focused component or is
281 * itself the focused component.
282 */
283 public static final int WHEN_ANCESTOR_OF_FOCUSED_COMPONENT = 1;
284
285 /**
286 * Constant used for <code>registerKeyboardAction</code> that
287 * means that the command should be invoked when
288 * the receiving component is in the window that has the focus
289 * or is itself the focused component.
290 */
291 public static final int WHEN_IN_FOCUSED_WINDOW = 2;
292
293 /**
294 * Constant used by some of the APIs to mean that no condition is defined.
295 */
296 public static final int UNDEFINED_CONDITION = -1;
297
298 /**
299 * The key used by <code>JComponent</code> to access keyboard bindings.
300 */
301 private static final String KEYBOARD_BINDINGS_KEY = "_KeyboardBindings";
302
303 /**
304 * An array of <code>KeyStroke</code>s used for
305 * <code>WHEN_IN_FOCUSED_WINDOW</code> are stashed
306 * in the client properties under this string.
307 */
308 private static final String WHEN_IN_FOCUSED_WINDOW_BINDINGS = "_WhenInFocusedWindow";
309
310 /**
311 * The comment to display when the cursor is over the component,
312 * also known as a "value tip", "flyover help", or "flyover label".
313 */
314 public static final String TOOL_TIP_TEXT_KEY = "ToolTipText";
315
316 private static final String NEXT_FOCUS = "nextFocus";
317
318 /**
319 * <code>JPopupMenu</code> assigned to this component
320 * and all of its childrens
321 */
322 private JPopupMenu popupMenu;
323
324 /** Private flags **/
325 private static final int IS_DOUBLE_BUFFERED = 0;
326 private static final int ANCESTOR_USING_BUFFER = 1;
327 private static final int IS_PAINTING_TILE = 2;
328 private static final int IS_OPAQUE = 3;
329 private static final int KEY_EVENTS_ENABLED = 4;
330 private static final int FOCUS_INPUTMAP_CREATED = 5;
331 private static final int ANCESTOR_INPUTMAP_CREATED = 6;
332 private static final int WIF_INPUTMAP_CREATED = 7;
333 private static final int ACTIONMAP_CREATED = 8;
334 private static final int CREATED_DOUBLE_BUFFER = 9;
335 // bit 10 is free
336 private static final int IS_PRINTING = 11;
337 private static final int IS_PRINTING_ALL = 12;
338 private static final int IS_REPAINTING = 13;
339 /** Bits 14-21 are used to handle nested writeObject calls. **/
340 private static final int WRITE_OBJ_COUNTER_FIRST = 14;
341 private static final int RESERVED_1 = 15;
342 private static final int RESERVED_2 = 16;
343 private static final int RESERVED_3 = 17;
344 private static final int RESERVED_4 = 18;
345 private static final int RESERVED_5 = 19;
346 private static final int RESERVED_6 = 20;
347 private static final int WRITE_OBJ_COUNTER_LAST = 21;
348
349 private static final int REQUEST_FOCUS_DISABLED = 22;
350 private static final int INHERITS_POPUP_MENU = 23;
351 private static final int OPAQUE_SET = 24;
352 private static final int AUTOSCROLLS_SET = 25;
353 private static final int FOCUS_TRAVERSAL_KEYS_FORWARD_SET = 26;
354 private static final int FOCUS_TRAVERSAL_KEYS_BACKWARD_SET = 27;
355 private static final int REVALIDATE_RUNNABLE_SCHEDULED = 28;
356
357 /**
358 * Temporary rectangles.
359 */
360 private static java.util.List<Rectangle> tempRectangles = new java.util.ArrayList<Rectangle>(11);
361
362 /** Used for <code>WHEN_FOCUSED</code> bindings. */
363 private InputMap focusInputMap;
364 /** Used for <code>WHEN_ANCESTOR_OF_FOCUSED_COMPONENT</code> bindings. */
365 private InputMap ancestorInputMap;
366 /** Used for <code>WHEN_IN_FOCUSED_KEY</code> bindings. */
367 private ComponentInputMap windowInputMap;
368
369 /** ActionMap. */
370 private ActionMap actionMap;
371
372 /** Key used to store the default locale in an AppContext **/
373 private static final String defaultLocale = "JComponent.defaultLocale";
374
375 private static Component componentObtainingGraphicsFrom;
376 private static Object componentObtainingGraphicsFromLock = new
377 StringBuilder("componentObtainingGraphicsFrom");
378
379 /**
380 * AA text hints.
381 */
382 transient private Object aaTextInfo;
383
384 static Graphics safelyGetGraphics(Component c) {
385 return safelyGetGraphics(c, SwingUtilities.getRoot(c));
386 }
387
388 static Graphics safelyGetGraphics(Component c, Component root) {
389 synchronized(componentObtainingGraphicsFromLock) {
390 componentObtainingGraphicsFrom = root;
391 Graphics g = c.getGraphics();
392 componentObtainingGraphicsFrom = null;
393 return g;
394 }
395 }
396
397 static void getGraphicsInvoked(Component root) {
398 if (!JComponent.isComponentObtainingGraphicsFrom(root)) {
399 JRootPane rootPane = ((RootPaneContainer)root).getRootPane();
400 if (rootPane != null) {
401 rootPane.disableTrueDoubleBuffering();
402 }
403 }
404 }
405
406
407 /**
408 * Returns true if {@code c} is the component the graphics is being
409 * requested of. This is intended for use when getGraphics is invoked.
410 */
411 private static boolean isComponentObtainingGraphicsFrom(Component c) {
412 synchronized(componentObtainingGraphicsFromLock) {
413 return (componentObtainingGraphicsFrom == c);
414 }
415 }
416
417 /**
418 * Returns the Set of <code>KeyStroke</code>s to use if the component
419 * is managing focus for forward focus traversal.
420 */
421 static Set<KeyStroke> getManagingFocusForwardTraversalKeys() {
422 synchronized(JComponent.class) {
423 if (managingFocusForwardTraversalKeys == null) {
424 managingFocusForwardTraversalKeys = new HashSet<KeyStroke>(1);
425 managingFocusForwardTraversalKeys.add(
426 KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
427 InputEvent.CTRL_MASK));
428 }
429 }
430 return managingFocusForwardTraversalKeys;
431 }
432
433 /**
434 * Returns the Set of <code>KeyStroke</code>s to use if the component
435 * is managing focus for backward focus traversal.
436 */
437 static Set<KeyStroke> getManagingFocusBackwardTraversalKeys() {
438 synchronized(JComponent.class) {
439 if (managingFocusBackwardTraversalKeys == null) {
440 managingFocusBackwardTraversalKeys = new HashSet<KeyStroke>(1);
441 managingFocusBackwardTraversalKeys.add(
442 KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
443 InputEvent.SHIFT_MASK |
444 InputEvent.CTRL_MASK));
445 }
446 }
447 return managingFocusBackwardTraversalKeys;
448 }
449
450 private static Rectangle fetchRectangle() {
451 synchronized(tempRectangles) {
452 Rectangle rect;
453 int size = tempRectangles.size();
454 if (size > 0) {
455 rect = tempRectangles.remove(size - 1);
456 }
457 else {
458 rect = new Rectangle(0, 0, 0, 0);
459 }
460 return rect;
461 }
462 }
463
464 private static void recycleRectangle(Rectangle rect) {
465 synchronized(tempRectangles) {
466 tempRectangles.add(rect);
467 }
468 }
469
470 /**
471 * Sets whether or not <code>getComponentPopupMenu</code> should delegate
472 * to the parent if this component does not have a <code>JPopupMenu</code>
473 * assigned to it.
474 * <p>
475 * The default value for this is false, but some <code>JComponent</code>
476 * subclasses that are implemented as a number of <code>JComponent</code>s
477 * may set this to true.
478 * <p>
479 * This is a bound property.
480 *
481 * @param value whether or not the JPopupMenu is inherited
482 * @see #setComponentPopupMenu
483 * @beaninfo
484 * bound: true
485 * description: Whether or not the JPopupMenu is inherited
486 * @since 1.5
487 */
488 public void setInheritsPopupMenu(boolean value) {
489 boolean oldValue = getFlag(INHERITS_POPUP_MENU);
490 setFlag(INHERITS_POPUP_MENU, value);
491 firePropertyChange("inheritsPopupMenu", oldValue, value);
492 }
493
494 /**
495 * Returns true if the JPopupMenu should be inherited from the parent.
496 *
497 * @see #setComponentPopupMenu
498 * @since 1.5
499 */
500 public boolean getInheritsPopupMenu() {
501 return getFlag(INHERITS_POPUP_MENU);
502 }
503
504 /**
505 * Sets the <code>JPopupMenu</code> for this <code>JComponent</code>.
506 * The UI is responsible for registering bindings and adding the necessary
507 * listeners such that the <code>JPopupMenu</code> will be shown at
508 * the appropriate time. When the <code>JPopupMenu</code> is shown
509 * depends upon the look and feel: some may show it on a mouse event,
510 * some may enable a key binding.
511 * <p>
512 * If <code>popup</code> is null, and <code>getInheritsPopupMenu</code>
513 * returns true, then <code>getComponentPopupMenu</code> will be delegated
514 * to the parent. This provides for a way to make all child components
515 * inherit the popupmenu of the parent.
516 * <p>
517 * This is a bound property.
518 *
519 * @param popup - the popup that will be assigned to this component
520 * may be null
521 * @see #getComponentPopupMenu
522 * @beaninfo
523 * bound: true
524 * preferred: true
525 * description: Popup to show
526 * @since 1.5
527 */
528 public void setComponentPopupMenu(JPopupMenu popup) {
529 if(popup != null) {
530 enableEvents(AWTEvent.MOUSE_EVENT_MASK);
531 }
532 JPopupMenu oldPopup = this.popupMenu;
533 this.popupMenu = popup;
534 firePropertyChange("componentPopupMenu", oldPopup, popup);
535 }
536
537 /**
538 * Returns <code>JPopupMenu</code> that assigned for this component.
539 * If this component does not have a <code>JPopupMenu</code> assigned
540 * to it and <code>getInheritsPopupMenu</code> is true, this
541 * will return <code>getParent().getComponentPopupMenu()</code> (assuming
542 * the parent is valid.)
543 *
544 * @return <code>JPopupMenu</code> assigned for this component
545 * or <code>null</code> if no popup assigned
546 * @see #setComponentPopupMenu
547 * @since 1.5
548 */
549 public JPopupMenu getComponentPopupMenu() {
550
551 if(!getInheritsPopupMenu()) {
552 return popupMenu;
553 }
554
555 if(popupMenu == null) {
556 // Search parents for its popup
557 Container parent = getParent();
558 while (parent != null) {
559 if(parent instanceof JComponent) {
560 return ((JComponent)parent).getComponentPopupMenu();
561 }
562 if(parent instanceof Window ||
563 parent instanceof Applet) {
564 // Reached toplevel, break and return null
565 break;
566 }
567 parent = parent.getParent();
568 }
569 return null;
570 }
571
572 return popupMenu;
573 }
574
575 /**
576 * Default <code>JComponent</code> constructor. This constructor does
577 * very little initialization beyond calling the <code>Container</code>
578 * constructor. For example, the initial layout manager is
579 * <code>null</code>. It does, however, set the component's locale
580 * property to the value returned by
581 * <code>JComponent.getDefaultLocale</code>.
582 *
583 * @see #getDefaultLocale
584 */
585 public JComponent() {
586 super();
587 // We enable key events on all JComponents so that accessibility
588 // bindings will work everywhere. This is a partial fix to BugID
589 // 4282211.
590 enableEvents(AWTEvent.KEY_EVENT_MASK);
591 if (isManagingFocus()) {
592 LookAndFeel.installProperty(this,
593 "focusTraversalKeysForward",
594 getManagingFocusForwardTraversalKeys());
595 LookAndFeel.installProperty(this,
596 "focusTraversalKeysBackward",
597 getManagingFocusBackwardTraversalKeys());
598 }
599
600 super.setLocale( JComponent.getDefaultLocale() );
601 }
602
603
604 /**
605 * Resets the UI property to a value from the current look and feel.
606 * <code>JComponent</code> subclasses must override this method
607 * like this:
608 * <pre>
609 * public void updateUI() {
610 * setUI((SliderUI)UIManager.getUI(this);
611 * }
612 * </pre>
613 *
614 * @see #setUI
615 * @see UIManager#getLookAndFeel
616 * @see UIManager#getUI
617 */
618 public void updateUI() {}
619
620
621 /**
622 * Sets the look and feel delegate for this component.
623 * <code>JComponent</code> subclasses generally override this method
624 * to narrow the argument type. For example, in <code>JSlider</code>:
625 * <pre>
626 * public void setUI(SliderUI newUI) {
627 * super.setUI(newUI);
628 * }
629 * </pre>
630 * <p>
631 * Additionally <code>JComponent</code> subclasses must provide a
632 * <code>getUI</code> method that returns the correct type. For example:
633 * <pre>
634 * public SliderUI getUI() {
635 * return (SliderUI)ui;
636 * }
637 * </pre>
638 *
639 * @param newUI the new UI delegate
640 * @see #updateUI
641 * @see UIManager#getLookAndFeel
642 * @see UIManager#getUI
643 * @beaninfo
644 * bound: true
645 * hidden: true
646 * attribute: visualUpdate true
647 * description: The component's look and feel delegate.
648 */
649 protected void setUI(ComponentUI newUI) {
650 /* We do not check that the UI instance is different
651 * before allowing the switch in order to enable the
652 * same UI instance *with different default settings*
653 * to be installed.
654 */
655
656 uninstallUIAndProperties();
657
658 // aaText shouldn't persist between look and feels, reset it.
659 aaTextInfo =
660 UIManager.getDefaults().get(SwingUtilities2.AA_TEXT_PROPERTY_KEY);
661 ComponentUI oldUI = ui;
662 ui = newUI;
663 if (ui != null) {
664 ui.installUI(this);
665 }
666
667 firePropertyChange("UI", oldUI, newUI);
668 revalidate();
669 repaint();
670 }
671
672 /**
673 * Uninstalls the UI, if any, and any client properties designated
674 * as being specific to the installed UI - instances of
675 * {@code UIClientPropertyKey}.
676 */
677 private void uninstallUIAndProperties() {
678 if (ui != null) {
679 ui.uninstallUI(this);
680 //clean UIClientPropertyKeys from client properties
681 if (clientProperties != null) {
682 synchronized(clientProperties) {
683 Object[] clientPropertyKeys =
684 clientProperties.getKeys(null);
685 if (clientPropertyKeys != null) {
686 for (Object key : clientPropertyKeys) {
687 if (key instanceof UIClientPropertyKey) {
688 putClientProperty(key, null);
689 }
690 }
691 }
692 }
693 }
694 }
695 }
696
697 /**
698 * Returns the <code>UIDefaults</code> key used to
699 * look up the name of the <code>swing.plaf.ComponentUI</code>
700 * class that defines the look and feel
701 * for this component. Most applications will never need to
702 * call this method. Subclasses of <code>JComponent</code> that support
703 * pluggable look and feel should override this method to
704 * return a <code>UIDefaults</code> key that maps to the
705 * <code>ComponentUI</code> subclass that defines their look and feel.
706 *
707 * @return the <code>UIDefaults</code> key for a
708 * <code>ComponentUI</code> subclass
709 * @see UIDefaults#getUI
710 * @beaninfo
711 * expert: true
712 * description: UIClassID
713 */
714 public String getUIClassID() {
715 return uiClassID;
716 }
717
718
719 /**
720 * Returns the graphics object used to paint this component.
721 * If <code>DebugGraphics</code> is turned on we create a new
722 * <code>DebugGraphics</code> object if necessary.
723 * Otherwise we just configure the
724 * specified graphics object's foreground and font.
725 *
726 * @param g the original <code>Graphics</code> object
727 * @return a <code>Graphics</code> object configured for this component
728 */
729 protected Graphics getComponentGraphics(Graphics g) {
730 Graphics componentGraphics = g;
731 if (ui != null && DEBUG_GRAPHICS_LOADED) {
732 if ((DebugGraphics.debugComponentCount() != 0) &&
733 (shouldDebugGraphics() != 0) &&
734 !(g instanceof DebugGraphics)) {
735 componentGraphics = new DebugGraphics(g,this);
736 }
737 }
738 componentGraphics.setColor(getForeground());
739 componentGraphics.setFont(getFont());
740
741 return componentGraphics;
742 }
743
744
745 /**
746 * Calls the UI delegate's paint method, if the UI delegate
747 * is non-<code>null</code>. We pass the delegate a copy of the
748 * <code>Graphics</code> object to protect the rest of the
749 * paint code from irrevocable changes
750 * (for example, <code>Graphics.translate</code>).
751 * <p>
752 * If you override this in a subclass you should not make permanent
753 * changes to the passed in <code>Graphics</code>. For example, you
754 * should not alter the clip <code>Rectangle</code> or modify the
755 * transform. If you need to do these operations you may find it
756 * easier to create a new <code>Graphics</code> from the passed in
757 * <code>Graphics</code> and manipulate it. Further, if you do not
758 * invoker super's implementation you must honor the opaque property,
759 * that is
760 * if this component is opaque, you must completely fill in the background
761 * in a non-opaque color. If you do not honor the opaque property you
762 * will likely see visual artifacts.
763 * <p>
764 * The passed in <code>Graphics</code> object might
765 * have a transform other than the identify transform
766 * installed on it. In this case, you might get
767 * unexpected results if you cumulatively apply
768 * another transform.
769 *
770 * @param g the <code>Graphics</code> object to protect
771 * @see #paint
772 * @see ComponentUI
773 */
774 protected void paintComponent(Graphics g) {
775 if (ui != null) {
776 Graphics scratchGraphics = (g == null) ? null : g.create();
777 try {
778 ui.update(scratchGraphics, this);
779 }
780 finally {
781 scratchGraphics.dispose();
782 }
783 }
784 }
785
786 /**
787 * Paints this component's children.
788 * If <code>shouldUseBuffer</code> is true,
789 * no component ancestor has a buffer and
790 * the component children can use a buffer if they have one.
791 * Otherwise, one ancestor has a buffer currently in use and children
792 * should not use a buffer to paint.
793 * @param g the <code>Graphics</code> context in which to paint
794 * @see #paint
795 * @see java.awt.Container#paint
796 */
797 protected void paintChildren(Graphics g) {
798 Graphics sg = g;
799
800 synchronized(getTreeLock()) {
801 int i = getComponentCount() - 1;
802 if (i < 0) {
803 return;
804 }
805 // If we are only to paint to a specific child, determine
806 // its index.
807 if (paintingChild != null &&
808 (paintingChild instanceof JComponent) &&
809 paintingChild.isOpaque()) {
810 for (; i >= 0; i--) {
811 if (getComponent(i) == paintingChild){
812 break;
813 }
814 }
815 }
816 Rectangle tmpRect = fetchRectangle();
817 boolean checkSiblings = (!isOptimizedDrawingEnabled() &&
818 checkIfChildObscuredBySibling());
819 Rectangle clipBounds = null;
820 if (checkSiblings) {
821 clipBounds = sg.getClipBounds();
822 if (clipBounds == null) {
823 clipBounds = new Rectangle(0, 0, getWidth(),
824 getHeight());
825 }
826 }
827 boolean printing = getFlag(IS_PRINTING);
828 final Window window = SwingUtilities.getWindowAncestor(this);
829 final boolean isWindowOpaque = window == null || window.isOpaque();
830 for (; i >= 0 ; i--) {
831 Component comp = getComponent(i);
832 if (comp == null) {
833 continue;
834 }
835
836 final boolean isJComponent = comp instanceof JComponent;
837
838 // Enable painting of heavyweights in non-opaque windows.
839 // See 6884960
840 if ((!isWindowOpaque || isJComponent ||
841 isLightweightComponent(comp)) && comp.isVisible())
842 {
843 Rectangle cr;
844
845 cr = comp.getBounds(tmpRect);
846
847 boolean hitClip = g.hitClip(cr.x, cr.y, cr.width,
848 cr.height);
849
850 if (hitClip) {
851 if (checkSiblings && i > 0) {
852 int x = cr.x;
853 int y = cr.y;
854 int width = cr.width;
855 int height = cr.height;
856 SwingUtilities.computeIntersection
857 (clipBounds.x, clipBounds.y,
858 clipBounds.width, clipBounds.height, cr);
859
860 if(getObscuredState(i, cr.x, cr.y, cr.width,
861 cr.height) == COMPLETELY_OBSCURED) {
862 continue;
863 }
864 cr.x = x;
865 cr.y = y;
866 cr.width = width;
867 cr.height = height;
868 }
869 Graphics cg = sg.create(cr.x, cr.y, cr.width,
870 cr.height);
871 cg.setColor(comp.getForeground());
872 cg.setFont(comp.getFont());
873 boolean shouldSetFlagBack = false;
874 try {
875 if(isJComponent) {
876 if(getFlag(ANCESTOR_USING_BUFFER)) {
877 ((JComponent)comp).setFlag(
878 ANCESTOR_USING_BUFFER,true);
879 shouldSetFlagBack = true;
880 }
881 if(getFlag(IS_PAINTING_TILE)) {
882 ((JComponent)comp).setFlag(
883 IS_PAINTING_TILE,true);
884 shouldSetFlagBack = true;
885 }
886 if(!printing) {
887 comp.paint(cg);
888 }
889 else {
890 if (!getFlag(IS_PRINTING_ALL)) {
891 comp.print(cg);
892 }
893 else {
894 comp.printAll(cg);
895 }
896 }
897 } else {
898 // The component is either lightweight, or
899 // heavyweight in a non-opaque window
900 if (!printing) {
901 comp.paint(cg);
902 }
903 else {
904 if (!getFlag(IS_PRINTING_ALL)) {
905 comp.print(cg);
906 }
907 else {
908 comp.printAll(cg);
909 }
910 }
911 }
912 } finally {
913 cg.dispose();
914 if(shouldSetFlagBack) {
915 ((JComponent)comp).setFlag(
916 ANCESTOR_USING_BUFFER,false);
917 ((JComponent)comp).setFlag(
918 IS_PAINTING_TILE,false);
919 }
920 }
921 }
922 }
923
924 }
925 recycleRectangle(tmpRect);
926 }
927 }
928
929 /**
930 * Paints the component's border.
931 * <p>
932 * If you override this in a subclass you should not make permanent
933 * changes to the passed in <code>Graphics</code>. For example, you
934 * should not alter the clip <code>Rectangle</code> or modify the
935 * transform. If you need to do these operations you may find it
936 * easier to create a new <code>Graphics</code> from the passed in
937 * <code>Graphics</code> and manipulate it.
938 *
939 * @param g the <code>Graphics</code> context in which to paint
940 *
941 * @see #paint
942 * @see #setBorder
943 */
944 protected void paintBorder(Graphics g) {
945 Border border = getBorder();
946 if (border != null) {
947 border.paintBorder(this, g, 0, 0, getWidth(), getHeight());
948 }
949 }
950
951
952 /**
953 * Calls <code>paint</code>. Doesn't clear the background but see
954 * <code>ComponentUI.update</code>, which is called by
955 * <code>paintComponent</code>.
956 *
957 * @param g the <code>Graphics</code> context in which to paint
958 * @see #paint
959 * @see #paintComponent
960 * @see javax.swing.plaf.ComponentUI
961 */
962 public void update(Graphics g) {
963 paint(g);
964 }
965
966
967 /**
968 * Invoked by Swing to draw components.
969 * Applications should not invoke <code>paint</code> directly,
970 * but should instead use the <code>repaint</code> method to
971 * schedule the component for redrawing.
972 * <p>
973 * This method actually delegates the work of painting to three
974 * protected methods: <code>paintComponent</code>,
975 * <code>paintBorder</code>,
976 * and <code>paintChildren</code>. They're called in the order
977 * listed to ensure that children appear on top of component itself.
978 * Generally speaking, the component and its children should not
979 * paint in the insets area allocated to the border. Subclasses can
980 * just override this method, as always. A subclass that just
981 * wants to specialize the UI (look and feel) delegate's
982 * <code>paint</code> method should just override
983 * <code>paintComponent</code>.
984 *
985 * @param g the <code>Graphics</code> context in which to paint
986 * @see #paintComponent
987 * @see #paintBorder
988 * @see #paintChildren
989 * @see #getComponentGraphics
990 * @see #repaint
991 */
992 public void paint(Graphics g) {
993 boolean shouldClearPaintFlags = false;
994
995 if ((getWidth() <= 0) || (getHeight() <= 0)) {
996 return;
997 }
998
999 Graphics componentGraphics = getComponentGraphics(g);
1000 Graphics co = componentGraphics.create();
1001 try {
1002 RepaintManager repaintManager = RepaintManager.currentManager(this);
1003 Rectangle clipRect = co.getClipBounds();
1004 int clipX;
1005 int clipY;
1006 int clipW;
1007 int clipH;
1008 if (clipRect == null) {
1009 clipX = clipY = 0;
1010 clipW = getWidth();
1011 clipH = getHeight();
1012 }
1013 else {
1014 clipX = clipRect.x;
1015 clipY = clipRect.y;
1016 clipW = clipRect.width;
1017 clipH = clipRect.height;
1018 }
1019
1020 if(clipW > getWidth()) {
1021 clipW = getWidth();
1022 }
1023 if(clipH > getHeight()) {
1024 clipH = getHeight();
1025 }
1026
1027 if(getParent() != null && !(getParent() instanceof JComponent)) {
1028 adjustPaintFlags();
1029 shouldClearPaintFlags = true;
1030 }
1031
1032 int bw,bh;
1033 boolean printing = getFlag(IS_PRINTING);
1034 if (!printing && repaintManager.isDoubleBufferingEnabled() &&
1035 !getFlag(ANCESTOR_USING_BUFFER) && isDoubleBuffered() &&
1036 (getFlag(IS_REPAINTING) || repaintManager.isPainting()))
1037 {
1038 repaintManager.beginPaint();
1039 try {
1040 repaintManager.paint(this, this, co, clipX, clipY, clipW,
1041 clipH);
1042 } finally {
1043 repaintManager.endPaint();
1044 }
1045 }
1046 else {
1047 // Will ocassionaly happen in 1.2, especially when printing.
1048 if (clipRect == null) {
1049 co.setClip(clipX, clipY, clipW, clipH);
1050 }
1051
1052 if (!rectangleIsObscured(clipX,clipY,clipW,clipH)) {
1053 if (!printing) {
1054 paintComponent(co);
1055 paintBorder(co);
1056 }
1057 else {
1058 printComponent(co);
1059 printBorder(co);
1060 }
1061 }
1062 if (!printing) {
1063 paintChildren(co);
1064 }
1065 else {
1066 printChildren(co);
1067 }
1068 }
1069 } finally {
1070 co.dispose();
1071 if(shouldClearPaintFlags) {
1072 setFlag(ANCESTOR_USING_BUFFER,false);
1073 setFlag(IS_PAINTING_TILE,false);
1074 setFlag(IS_PRINTING,false);
1075 setFlag(IS_PRINTING_ALL,false);
1076 }
1077 }
1078 }
1079
1080 // paint forcing use of the double buffer. This is used for historical
1081 // reasons: JViewport, when scrolling, previously directly invoked paint
1082 // while turning off double buffering at the RepaintManager level, this
1083 // codes simulates that.
1084 void paintForceDoubleBuffered(Graphics g) {
1085 RepaintManager rm = RepaintManager.currentManager(this);
1086 Rectangle clip = g.getClipBounds();
1087 rm.beginPaint();
1088 setFlag(IS_REPAINTING, true);
1089 try {
1090 rm.paint(this, this, g, clip.x, clip.y, clip.width, clip.height);
1091 } finally {
1092 rm.endPaint();
1093 setFlag(IS_REPAINTING, false);
1094 }
1095 }
1096
1097 /**
1098 * Returns true if this component, or any of its ancestors, are in
1099 * the processing of painting.
1100 */
1101 boolean isPainting() {
1102 Container component = this;
1103 while (component != null) {
1104 if (component instanceof JComponent &&
1105 ((JComponent)component).getFlag(ANCESTOR_USING_BUFFER)) {
1106 return true;
1107 }
1108 component = component.getParent();
1109 }
1110 return false;
1111 }
1112
1113 private void adjustPaintFlags() {
1114 JComponent jparent;
1115 Container parent;
1116 for(parent = getParent() ; parent != null ; parent =
1117 parent.getParent()) {
1118 if(parent instanceof JComponent) {
1119 jparent = (JComponent) parent;
1120 if(jparent.getFlag(ANCESTOR_USING_BUFFER))
1121 setFlag(ANCESTOR_USING_BUFFER, true);
1122 if(jparent.getFlag(IS_PAINTING_TILE))
1123 setFlag(IS_PAINTING_TILE, true);
1124 if(jparent.getFlag(IS_PRINTING))
1125 setFlag(IS_PRINTING, true);
1126 if(jparent.getFlag(IS_PRINTING_ALL))
1127 setFlag(IS_PRINTING_ALL, true);
1128 break;
1129 }
1130 }
1131 }
1132
1133 /**
1134 * Invoke this method to print the component. This method invokes
1135 * <code>print</code> on the component.
1136 *
1137 * @param g the <code>Graphics</code> context in which to paint
1138 * @see #print
1139 * @see #printComponent
1140 * @see #printBorder
1141 * @see #printChildren
1142 */
1143 public void printAll(Graphics g) {
1144 setFlag(IS_PRINTING_ALL, true);
1145 try {
1146 print(g);
1147 }
1148 finally {
1149 setFlag(IS_PRINTING_ALL, false);
1150 }
1151 }
1152
1153 /**
1154 * Invoke this method to print the component to the specified
1155 * <code>Graphics</code>. This method will result in invocations
1156 * of <code>printComponent</code>, <code>printBorder</code> and
1157 * <code>printChildren</code>. It is recommended that you override
1158 * one of the previously mentioned methods rather than this one if
1159 * your intention is to customize the way printing looks. However,
1160 * it can be useful to override this method should you want to prepare
1161 * state before invoking the superclass behavior. As an example,
1162 * if you wanted to change the component's background color before
1163 * printing, you could do the following:
1164 * <pre>
1165 * public void print(Graphics g) {
1166 * Color orig = getBackground();
1167 * setBackground(Color.WHITE);
1168 *
1169 * // wrap in try/finally so that we always restore the state
1170 * try {
1171 * super.print(g);
1172 * } finally {
1173 * setBackground(orig);
1174 * }
1175 * }
1176 * </pre>
1177 * <p>
1178 * Alternatively, or for components that delegate painting to other objects,
1179 * you can query during painting whether or not the component is in the
1180 * midst of a print operation. The <code>isPaintingForPrint</code> method provides
1181 * this ability and its return value will be changed by this method: to
1182 * <code>true</code> immediately before rendering and to <code>false</code>
1183 * immediately after. With each change a property change event is fired on
1184 * this component with the name <code>"paintingForPrint"</code>.
1185 * <p>
1186 * This method sets the component's state such that the double buffer
1187 * will not be used: painting will be done directly on the passed in
1188 * <code>Graphics</code>.
1189 *
1190 * @param g the <code>Graphics</code> context in which to paint
1191 * @see #printComponent
1192 * @see #printBorder
1193 * @see #printChildren
1194 * @see #isPaintingForPrint
1195 */
1196 public void print(Graphics g) {
1197 setFlag(IS_PRINTING, true);
1198 firePropertyChange("paintingForPrint", false, true);
1199 try {
1200 paint(g);
1201 }
1202 finally {
1203 setFlag(IS_PRINTING, false);
1204 firePropertyChange("paintingForPrint", true, false);
1205 }
1206 }
1207
1208 /**
1209 * This is invoked during a printing operation. This is implemented to
1210 * invoke <code>paintComponent</code> on the component. Override this
1211 * if you wish to add special painting behavior when printing.
1212 *
1213 * @param g the <code>Graphics</code> context in which to paint
1214 * @see #print
1215 * @since 1.3
1216 */
1217 protected void printComponent(Graphics g) {
1218 paintComponent(g);
1219 }
1220
1221 /**
1222 * Prints this component's children. This is implemented to invoke
1223 * <code>paintChildren</code> on the component. Override this if you
1224 * wish to print the children differently than painting.
1225 *
1226 * @param g the <code>Graphics</code> context in which to paint
1227 * @see #print
1228 * @since 1.3
1229 */
1230 protected void printChildren(Graphics g) {
1231 paintChildren(g);
1232 }
1233
1234 /**
1235 * Prints the component's border. This is implemented to invoke
1236 * <code>paintBorder</code> on the component. Override this if you
1237 * wish to print the border differently that it is painted.
1238 *
1239 * @param g the <code>Graphics</code> context in which to paint
1240 * @see #print
1241 * @since 1.3
1242 */
1243 protected void printBorder(Graphics g) {
1244 paintBorder(g);
1245 }
1246
1247 /**
1248 * Returns true if the component is currently painting a tile.
1249 * If this method returns true, paint will be called again for another
1250 * tile. This method returns false if you are not painting a tile or
1251 * if the last tile is painted.
1252 * Use this method to keep some state you might need between tiles.
1253 *
1254 * @return true if the component is currently painting a tile,
1255 * false otherwise
1256 */
1257 public boolean isPaintingTile() {
1258 return getFlag(IS_PAINTING_TILE);
1259 }
1260
1261 /**
1262 * Returns <code>true</code> if the current painting operation on this
1263 * component is part of a <code>print</code> operation. This method is
1264 * useful when you want to customize what you print versus what you show
1265 * on the screen.
1266 * <p>
1267 * You can detect changes in the value of this property by listening for
1268 * property change events on this component with name
1269 * <code>"paintingForPrint"</code>.
1270 * <p>
1271 * Note: This method provides complimentary functionality to that provided
1272 * by other high level Swing printing APIs. However, it deals strictly with
1273 * painting and should not be confused as providing information on higher
1274 * level print processes. For example, a {@link javax.swing.JTable#print()}
1275 * operation doesn't necessarily result in a continuous rendering of the
1276 * full component, and the return value of this method can change multiple
1277 * times during that operation. It is even possible for the component to be
1278 * painted to the screen while the printing process is ongoing. In such a
1279 * case, the return value of this method is <code>true</code> when, and only
1280 * when, the table is being painted as part of the printing process.
1281 *
1282 * @return true if the current painting operation on this component
1283 * is part of a print operation
1284 * @see #print
1285 * @since 1.6
1286 */
1287 public final boolean isPaintingForPrint() {
1288 return getFlag(IS_PRINTING);
1289 }
1290
1291 /**
1292 * In release 1.4, the focus subsystem was rearchitected.
1293 * For more information, see
1294 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
1295 * How to Use the Focus Subsystem</a>,
1296 * a section in <em>The Java Tutorial</em>.
1297 * <p>
1298 * Changes this <code>JComponent</code>'s focus traversal keys to
1299 * CTRL+TAB and CTRL+SHIFT+TAB. Also prevents
1300 * <code>SortingFocusTraversalPolicy</code> from considering descendants
1301 * of this JComponent when computing a focus traversal cycle.
1302 *
1303 * @see java.awt.Component#setFocusTraversalKeys
1304 * @see SortingFocusTraversalPolicy
1305 * @deprecated As of 1.4, replaced by
1306 * <code>Component.setFocusTraversalKeys(int, Set)</code> and
1307 * <code>Container.setFocusCycleRoot(boolean)</code>.
1308 */
1309 @Deprecated
1310 public boolean isManagingFocus() {
1311 return false;
1312 }
1313
1314 private void registerNextFocusableComponent() {
1315 registerNextFocusableComponent(getNextFocusableComponent());
1316 }
1317
1318 private void registerNextFocusableComponent(Component
1319 nextFocusableComponent) {
1320 if (nextFocusableComponent == null) {
1321 return;
1322 }
1323
1324 Container nearestRoot =
1325 (isFocusCycleRoot()) ? this : getFocusCycleRootAncestor();
1326 FocusTraversalPolicy policy = nearestRoot.getFocusTraversalPolicy();
1327 if (!(policy instanceof LegacyGlueFocusTraversalPolicy)) {
1328 policy = new LegacyGlueFocusTraversalPolicy(policy);
1329 nearestRoot.setFocusTraversalPolicy(policy);
1330 }
1331 ((LegacyGlueFocusTraversalPolicy)policy).
1332 setNextFocusableComponent(this, nextFocusableComponent);
1333 }
1334
1335 private void deregisterNextFocusableComponent() {
1336 Component nextFocusableComponent = getNextFocusableComponent();
1337 if (nextFocusableComponent == null) {
1338 return;
1339 }
1340
1341 Container nearestRoot =
1342 (isFocusCycleRoot()) ? this : getFocusCycleRootAncestor();
1343 if (nearestRoot == null) {
1344 return;
1345 }
1346 FocusTraversalPolicy policy = nearestRoot.getFocusTraversalPolicy();
1347 if (policy instanceof LegacyGlueFocusTraversalPolicy) {
1348 ((LegacyGlueFocusTraversalPolicy)policy).
1349 unsetNextFocusableComponent(this, nextFocusableComponent);
1350 }
1351 }
1352
1353 /**
1354 * In release 1.4, the focus subsystem was rearchitected.
1355 * For more information, see
1356 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
1357 * How to Use the Focus Subsystem</a>,
1358 * a section in <em>The Java Tutorial</em>.
1359 * <p>
1360 * Overrides the default <code>FocusTraversalPolicy</code> for this
1361 * <code>JComponent</code>'s focus traversal cycle by unconditionally
1362 * setting the specified <code>Component</code> as the next
1363 * <code>Component</code> in the cycle, and this <code>JComponent</code>
1364 * as the specified <code>Component</code>'s previous
1365 * <code>Component</code> in the cycle.
1366 *
1367 * @param aComponent the <code>Component</code> that should follow this
1368 * <code>JComponent</code> in the focus traversal cycle
1369 *
1370 * @see #getNextFocusableComponent
1371 * @see java.awt.FocusTraversalPolicy
1372 * @deprecated As of 1.4, replaced by <code>FocusTraversalPolicy</code>
1373 */
1374 @Deprecated
1375 public void setNextFocusableComponent(Component aComponent) {
1376 boolean displayable = isDisplayable();
1377 if (displayable) {
1378 deregisterNextFocusableComponent();
1379 }
1380 putClientProperty(NEXT_FOCUS, aComponent);
1381 if (displayable) {
1382 registerNextFocusableComponent(aComponent);
1383 }
1384 }
1385
1386 /**
1387 * In release 1.4, the focus subsystem was rearchitected.
1388 * For more information, see
1389 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
1390 * How to Use the Focus Subsystem</a>,
1391 * a section in <em>The Java Tutorial</em>.
1392 * <p>
1393 * Returns the <code>Component</code> set by a prior call to
1394 * <code>setNextFocusableComponent(Component)</code> on this
1395 * <code>JComponent</code>.
1396 *
1397 * @return the <code>Component</code> that will follow this
1398 * <code>JComponent</code> in the focus traversal cycle, or
1399 * <code>null</code> if none has been explicitly specified
1400 *
1401 * @see #setNextFocusableComponent
1402 * @deprecated As of 1.4, replaced by <code>FocusTraversalPolicy</code>.
1403 */
1404 @Deprecated
1405 public Component getNextFocusableComponent() {
1406 return (Component)getClientProperty(NEXT_FOCUS);
1407 }
1408
1409 /**
1410 * Provides a hint as to whether or not this <code>JComponent</code>
1411 * should get focus. This is only a hint, and it is up to consumers that
1412 * are requesting focus to honor this property. This is typically honored
1413 * for mouse operations, but not keyboard operations. For example, look
1414 * and feels could verify this property is true before requesting focus
1415 * during a mouse operation. This would often times be used if you did
1416 * not want a mouse press on a <code>JComponent</code> to steal focus,
1417 * but did want the <code>JComponent</code> to be traversable via the
1418 * keyboard. If you do not want this <code>JComponent</code> focusable at
1419 * all, use the <code>setFocusable</code> method instead.
1420 * <p>
1421 * Please see
1422 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
1423 * How to Use the Focus Subsystem</a>,
1424 * a section in <em>The Java Tutorial</em>,
1425 * for more information.
1426 *
1427 * @param requestFocusEnabled indicates whether you want this
1428 * <code>JComponent</code> to be focusable or not
1429 * @see <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
1430 * @see java.awt.Component#setFocusable
1431 */
1432 public void setRequestFocusEnabled(boolean requestFocusEnabled) {
1433 setFlag(REQUEST_FOCUS_DISABLED, !requestFocusEnabled);
1434 }
1435
1436 /**
1437 * Returns <code>true</code> if this <code>JComponent</code> should
1438 * get focus; otherwise returns <code>false</code>.
1439 * <p>
1440 * Please see
1441 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
1442 * How to Use the Focus Subsystem</a>,
1443 * a section in <em>The Java Tutorial</em>,
1444 * for more information.
1445 *
1446 * @return <code>true</code> if this component should get focus,
1447 * otherwise returns <code>false</code>
1448 * @see #setRequestFocusEnabled
1449 * @see <a href="../../java/awt/doc-files/FocusSpec.html">Focus
1450 * Specification</a>
1451 * @see java.awt.Component#isFocusable
1452 */
1453 public boolean isRequestFocusEnabled() {
1454 return !getFlag(REQUEST_FOCUS_DISABLED);
1455 }
1456
1457 /**
1458 * Requests that this <code>Component</code> gets the input focus.
1459 * Refer to {@link java.awt.Component#requestFocus()
1460 * Component.requestFocus()} for a complete description of
1461 * this method.
1462 * <p>
1463 * Note that the use of this method is discouraged because
1464 * its behavior is platform dependent. Instead we recommend the
1465 * use of {@link #requestFocusInWindow() requestFocusInWindow()}.
1466 * If you would like more information on focus, see
1467 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
1468 * How to Use the Focus Subsystem</a>,
1469 * a section in <em>The Java Tutorial</em>.
1470 *
1471 * @see java.awt.Component#requestFocusInWindow()
1472 * @see java.awt.Component#requestFocusInWindow(boolean)
1473 * @since 1.4
1474 */
1475 public void requestFocus() {
1476 super.requestFocus();
1477 }
1478
1479 /**
1480 * Requests that this <code>Component</code> gets the input focus.
1481 * Refer to {@link java.awt.Component#requestFocus(boolean)
1482 * Component.requestFocus(boolean)} for a complete description of
1483 * this method.
1484 * <p>
1485 * Note that the use of this method is discouraged because
1486 * its behavior is platform dependent. Instead we recommend the
1487 * use of {@link #requestFocusInWindow(boolean)
1488 * requestFocusInWindow(boolean)}.
1489 * If you would like more information on focus, see
1490 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
1491 * How to Use the Focus Subsystem</a>,
1492 * a section in <em>The Java Tutorial</em>.
1493 *
1494 * @param temporary boolean indicating if the focus change is temporary
1495 * @return <code>false</code> if the focus change request is guaranteed to
1496 * fail; <code>true</code> if it is likely to succeed
1497 * @see java.awt.Component#requestFocusInWindow()
1498 * @see java.awt.Component#requestFocusInWindow(boolean)
1499 * @since 1.4
1500 */
1501 public boolean requestFocus(boolean temporary) {
1502 return super.requestFocus(temporary);
1503 }
1504
1505 /**
1506 * Requests that this <code>Component</code> gets the input focus.
1507 * Refer to {@link java.awt.Component#requestFocusInWindow()
1508 * Component.requestFocusInWindow()} for a complete description of
1509 * this method.
1510 * <p>
1511 * If you would like more information on focus, see
1512 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
1513 * How to Use the Focus Subsystem</a>,
1514 * a section in <em>The Java Tutorial</em>.
1515 *
1516 * @return <code>false</code> if the focus change request is guaranteed to
1517 * fail; <code>true</code> if it is likely to succeed
1518 * @see java.awt.Component#requestFocusInWindow()
1519 * @see java.awt.Component#requestFocusInWindow(boolean)
1520 * @since 1.4
1521 */
1522 public boolean requestFocusInWindow() {
1523 return super.requestFocusInWindow();
1524 }
1525
1526 /**
1527 * Requests that this <code>Component</code> gets the input focus.
1528 * Refer to {@link java.awt.Component#requestFocusInWindow(boolean)
1529 * Component.requestFocusInWindow(boolean)} for a complete description of
1530 * this method.
1531 * <p>
1532 * If you would like more information on focus, see
1533 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
1534 * How to Use the Focus Subsystem</a>,
1535 * a section in <em>The Java Tutorial</em>.
1536 *
1537 * @param temporary boolean indicating if the focus change is temporary
1538 * @return <code>false</code> if the focus change request is guaranteed to
1539 * fail; <code>true</code> if it is likely to succeed
1540 * @see java.awt.Component#requestFocusInWindow()
1541 * @see java.awt.Component#requestFocusInWindow(boolean)
1542 * @since 1.4
1543 */
1544 protected boolean requestFocusInWindow(boolean temporary) {
1545 return super.requestFocusInWindow(temporary);
1546 }
1547
1548 /**
1549 * Requests that this Component get the input focus, and that this
1550 * Component's top-level ancestor become the focused Window. This component
1551 * must be displayable, visible, and focusable for the request to be
1552 * granted.
1553 * <p>
1554 * This method is intended for use by focus implementations. Client code
1555 * should not use this method; instead, it should use
1556 * <code>requestFocusInWindow()</code>.
1557 *
1558 * @see #requestFocusInWindow()
1559 */
1560 public void grabFocus() {
1561 requestFocus();
1562 }
1563
1564 /**
1565 * Sets the value to indicate whether input verifier for the
1566 * current focus owner will be called before this component requests
1567 * focus. The default is true. Set to false on components such as a
1568 * Cancel button or a scrollbar, which should activate even if the
1569 * input in the current focus owner is not "passed" by the input
1570 * verifier for that component.
1571 *
1572 * @param verifyInputWhenFocusTarget value for the
1573 * <code>verifyInputWhenFocusTarget</code> property
1574 * @see InputVerifier
1575 * @see #setInputVerifier
1576 * @see #getInputVerifier
1577 * @see #getVerifyInputWhenFocusTarget
1578 *
1579 * @since 1.3
1580 * @beaninfo
1581 * bound: true
1582 * description: Whether the Component verifies input before accepting
1583 * focus.
1584 */
1585 public void setVerifyInputWhenFocusTarget(boolean
1586 verifyInputWhenFocusTarget) {
1587 boolean oldVerifyInputWhenFocusTarget =
1588 this.verifyInputWhenFocusTarget;
1589 this.verifyInputWhenFocusTarget = verifyInputWhenFocusTarget;
1590 firePropertyChange("verifyInputWhenFocusTarget",
1591 oldVerifyInputWhenFocusTarget,
1592 verifyInputWhenFocusTarget);
1593 }
1594
1595 /**
1596 * Returns the value that indicates whether the input verifier for the
1597 * current focus owner will be called before this component requests
1598 * focus.
1599 *
1600 * @return value of the <code>verifyInputWhenFocusTarget</code> property
1601 *
1602 * @see InputVerifier
1603 * @see #setInputVerifier
1604 * @see #getInputVerifier
1605 * @see #setVerifyInputWhenFocusTarget
1606 *
1607 * @since 1.3
1608 */
1609 public boolean getVerifyInputWhenFocusTarget() {
1610 return verifyInputWhenFocusTarget;
1611 }
1612
1613
1614 /**
1615 * Gets the <code>FontMetrics</code> for the specified <code>Font</code>.
1616 *
1617 * @param font the font for which font metrics is to be
1618 * obtained
1619 * @return the font metrics for <code>font</code>
1620 * @throws NullPointerException if <code>font</code> is null
1621 * @since 1.5
1622 */
1623 public FontMetrics getFontMetrics(Font font) {
1624 return SwingUtilities2.getFontMetrics(this, font);
1625 }
1626
1627
1628 /**
1629 * Sets the preferred size of this component.
1630 * If <code>preferredSize</code> is <code>null</code>, the UI will
1631 * be asked for the preferred size.
1632 * @beaninfo
1633 * preferred: true
1634 * bound: true
1635 * description: The preferred size of the component.
1636 */
1637 public void setPreferredSize(Dimension preferredSize) {
1638 super.setPreferredSize(preferredSize);
1639 }
1640
1641
1642 /**
1643 * If the <code>preferredSize</code> has been set to a
1644 * non-<code>null</code> value just returns it.
1645 * If the UI delegate's <code>getPreferredSize</code>
1646 * method returns a non <code>null</code> value then return that;
1647 * otherwise defer to the component's layout manager.
1648 *
1649 * @return the value of the <code>preferredSize</code> property
1650 * @see #setPreferredSize
1651 * @see ComponentUI
1652 */
1653 @Transient
1654 public Dimension getPreferredSize() {
1655 if (isPreferredSizeSet()) {
1656 return super.getPreferredSize();
1657 }
1658 Dimension size = null;
1659 if (ui != null) {
1660 size = ui.getPreferredSize(this);
1661 }
1662 return (size != null) ? size : super.getPreferredSize();
1663 }
1664
1665
1666 /**
1667 * Sets the maximum size of this component to a constant
1668 * value. Subsequent calls to <code>getMaximumSize</code> will always
1669 * return this value; the component's UI will not be asked
1670 * to compute it. Setting the maximum size to <code>null</code>
1671 * restores the default behavior.
1672 *
1673 * @param maximumSize a <code>Dimension</code> containing the
1674 * desired maximum allowable size
1675 * @see #getMaximumSize
1676 * @beaninfo
1677 * bound: true
1678 * description: The maximum size of the component.
1679 */
1680 public void setMaximumSize(Dimension maximumSize) {
1681 super.setMaximumSize(maximumSize);
1682 }
1683
1684
1685 /**
1686 * If the maximum size has been set to a non-<code>null</code> value
1687 * just returns it. If the UI delegate's <code>getMaximumSize</code>
1688 * method returns a non-<code>null</code> value then return that;
1689 * otherwise defer to the component's layout manager.
1690 *
1691 * @return the value of the <code>maximumSize</code> property
1692 * @see #setMaximumSize
1693 * @see ComponentUI
1694 */
1695 @Transient
1696 public Dimension getMaximumSize() {
1697 if (isMaximumSizeSet()) {
1698 return super.getMaximumSize();
1699 }
1700 Dimension size = null;
1701 if (ui != null) {
1702 size = ui.getMaximumSize(this);
1703 }
1704 return (size != null) ? size : super.getMaximumSize();
1705 }
1706
1707
1708 /**
1709 * Sets the minimum size of this component to a constant
1710 * value. Subsequent calls to <code>getMinimumSize</code> will always
1711 * return this value; the component's UI will not be asked
1712 * to compute it. Setting the minimum size to <code>null</code>
1713 * restores the default behavior.
1714 *
1715 * @param minimumSize the new minimum size of this component
1716 * @see #getMinimumSize
1717 * @beaninfo
1718 * bound: true
1719 * description: The minimum size of the component.
1720 */
1721 public void setMinimumSize(Dimension minimumSize) {
1722 super.setMinimumSize(minimumSize);
1723 }
1724
1725 /**
1726 * If the minimum size has been set to a non-<code>null</code> value
1727 * just returns it. If the UI delegate's <code>getMinimumSize</code>
1728 * method returns a non-<code>null</code> value then return that; otherwise
1729 * defer to the component's layout manager.
1730 *
1731 * @return the value of the <code>minimumSize</code> property
1732 * @see #setMinimumSize
1733 * @see ComponentUI
1734 */
1735 @Transient
1736 public Dimension getMinimumSize() {
1737 if (isMinimumSizeSet()) {
1738 return super.getMinimumSize();
1739 }
1740 Dimension size = null;
1741 if (ui != null) {
1742 size = ui.getMinimumSize(this);
1743 }
1744 return (size != null) ? size : super.getMinimumSize();
1745 }
1746
1747 /**
1748 * Gives the UI delegate an opportunity to define the precise
1749 * shape of this component for the sake of mouse processing.
1750 *
1751 * @return true if this component logically contains x,y
1752 * @see java.awt.Component#contains(int, int)
1753 * @see ComponentUI
1754 */
1755 public boolean contains(int x, int y) {
1756 return (ui != null) ? ui.contains(this, x, y) : super.contains(x, y);
1757 }
1758
1759 /**
1760 * Sets the border of this component. The <code>Border</code> object is
1761 * responsible for defining the insets for the component
1762 * (overriding any insets set directly on the component) and
1763 * for optionally rendering any border decorations within the
1764 * bounds of those insets. Borders should be used (rather
1765 * than insets) for creating both decorative and non-decorative
1766 * (such as margins and padding) regions for a swing component.
1767 * Compound borders can be used to nest multiple borders within a
1768 * single component.
1769 * <p>
1770 * Although technically you can set the border on any object
1771 * that inherits from <code>JComponent</code>, the look and
1772 * feel implementation of many standard Swing components
1773 * doesn't work well with user-set borders. In general,
1774 * when you want to set a border on a standard Swing
1775 * component other than <code>JPanel</code> or <code>JLabel</code>,
1776 * we recommend that you put the component in a <code>JPanel</code>
1777 * and set the border on the <code>JPanel</code>.
1778 * <p>
1779 * This is a bound property.
1780 *
1781 * @param border the border to be rendered for this component
1782 * @see Border
1783 * @see CompoundBorder
1784 * @beaninfo
1785 * bound: true
1786 * preferred: true
1787 * attribute: visualUpdate true
1788 * description: The component's border.
1789 */
1790 public void setBorder(Border border) {
1791 Border oldBorder = this.border;
1792
1793 this.border = border;
1794 firePropertyChange("border", oldBorder, border);
1795 if (border != oldBorder) {
1796 if (border == null || oldBorder == null ||
1797 !(border.getBorderInsets(this).equals(oldBorder.getBorderInsets(this)))) {
1798 revalidate();
1799 }
1800 repaint();
1801 }
1802 }
1803
1804 /**
1805 * Returns the border of this component or <code>null</code> if no
1806 * border is currently set.
1807 *
1808 * @return the border object for this component
1809 * @see #setBorder
1810 */
1811 public Border getBorder() {
1812 return border;
1813 }
1814
1815 /**
1816 * If a border has been set on this component, returns the
1817 * border's insets; otherwise calls <code>super.getInsets</code>.
1818 *
1819 * @return the value of the insets property
1820 * @see #setBorder
1821 */
1822 public Insets getInsets() {
1823 if (border != null) {
1824 return border.getBorderInsets(this);
1825 }
1826 return super.getInsets();
1827 }
1828
1829 /**
1830 * Returns an <code>Insets</code> object containing this component's inset
1831 * values. The passed-in <code>Insets</code> object will be reused
1832 * if possible.
1833 * Calling methods cannot assume that the same object will be returned,
1834 * however. All existing values within this object are overwritten.
1835 * If <code>insets</code> is null, this will allocate a new one.
1836 *
1837 * @param insets the <code>Insets</code> object, which can be reused
1838 * @return the <code>Insets</code> object
1839 * @see #getInsets
1840 * @beaninfo
1841 * expert: true
1842 */
1843 public Insets getInsets(Insets insets) {
1844 if (insets == null) {
1845 insets = new Insets(0, 0, 0, 0);
1846 }
1847 if (border != null) {
1848 if (border instanceof AbstractBorder) {
1849 return ((AbstractBorder)border).getBorderInsets(this, insets);
1850 } else {
1851 // Can't reuse border insets because the Border interface
1852 // can't be enhanced.
1853 return border.getBorderInsets(this);
1854 }
1855 } else {
1856 // super.getInsets() always returns an Insets object with
1857 // all of its value zeroed. No need for a new object here.
1858 insets.left = insets.top = insets.right = insets.bottom = 0;
1859 return insets;
1860 }
1861 }
1862
1863 /**
1864 * Overrides <code>Container.getAlignmentY</code> to return
1865 * the horizontal alignment.
1866 *
1867 * @return the value of the <code>alignmentY</code> property
1868 * @see #setAlignmentY
1869 * @see java.awt.Component#getAlignmentY
1870 */
1871 public float getAlignmentY() {
1872 if (isAlignmentYSet) {
1873 return alignmentY;
1874 }
1875 return super.getAlignmentY();
1876 }
1877
1878 /**
1879 * Sets the the horizontal alignment.
1880 *
1881 * @param alignmentY the new horizontal alignment
1882 * @see #getAlignmentY
1883 * @beaninfo
1884 * description: The preferred vertical alignment of the component.
1885 */
1886 public void setAlignmentY(float alignmentY) {
1887 this.alignmentY = alignmentY > 1.0f ? 1.0f : alignmentY < 0.0f ? 0.0f : alignmentY;
1888 isAlignmentYSet = true;
1889 }
1890
1891
1892 /**
1893 * Overrides <code>Container.getAlignmentX</code> to return
1894 * the vertical alignment.
1895 *
1896 * @return the value of the <code>alignmentX</code> property
1897 * @see #setAlignmentX
1898 * @see java.awt.Component#getAlignmentX
1899 */
1900 public float getAlignmentX() {
1901 if (isAlignmentXSet) {
1902 return alignmentX;
1903 }
1904 return super.getAlignmentX();
1905 }
1906
1907 /**
1908 * Sets the the vertical alignment.
1909 *
1910 * @param alignmentX the new vertical alignment
1911 * @see #getAlignmentX
1912 * @beaninfo
1913 * description: The preferred horizontal alignment of the component.
1914 */
1915 public void setAlignmentX(float alignmentX) {
1916 this.alignmentX = alignmentX > 1.0f ? 1.0f : alignmentX < 0.0f ? 0.0f : alignmentX;
1917 isAlignmentXSet = true;
1918 }
1919
1920 /**
1921 * Sets the input verifier for this component.
1922 *
1923 * @param inputVerifier the new input verifier
1924 * @since 1.3
1925 * @see InputVerifier
1926 * @beaninfo
1927 * bound: true
1928 * description: The component's input verifier.
1929 */
1930 public void setInputVerifier(InputVerifier inputVerifier) {
1931 InputVerifier oldInputVerifier = (InputVerifier)getClientProperty(
1932 JComponent_INPUT_VERIFIER);
1933 putClientProperty(JComponent_INPUT_VERIFIER, inputVerifier);
1934 firePropertyChange("inputVerifier", oldInputVerifier, inputVerifier);
1935 }
1936
1937 /**
1938 * Returns the input verifier for this component.
1939 *
1940 * @return the <code>inputVerifier</code> property
1941 * @since 1.3
1942 * @see InputVerifier
1943 */
1944 public InputVerifier getInputVerifier() {
1945 return (InputVerifier)getClientProperty(JComponent_INPUT_VERIFIER);
1946 }
1947
1948 /**
1949 * Returns this component's graphics context, which lets you draw
1950 * on a component. Use this method to get a <code>Graphics</code> object and
1951 * then invoke operations on that object to draw on the component.
1952 * @return this components graphics context
1953 */
1954 public Graphics getGraphics() {
1955 if (DEBUG_GRAPHICS_LOADED && shouldDebugGraphics() != 0) {
1956 DebugGraphics graphics = new DebugGraphics(super.getGraphics(),
1957 this);
1958 return graphics;
1959 }
1960 return super.getGraphics();
1961 }
1962
1963
1964 /** Enables or disables diagnostic information about every graphics
1965 * operation performed within the component or one of its children.
1966 *
1967 * @param debugOptions determines how the component should display
1968 * the information; one of the following options:
1969 * <ul>
1970 * <li>DebugGraphics.LOG_OPTION - causes a text message to be printed.
1971 * <li>DebugGraphics.FLASH_OPTION - causes the drawing to flash several
1972 * times.
1973 * <li>DebugGraphics.BUFFERED_OPTION - creates an
1974 * <code>ExternalWindow</code> that displays the operations
1975 * performed on the View's offscreen buffer.
1976 * <li>DebugGraphics.NONE_OPTION disables debugging.
1977 * <li>A value of 0 causes no changes to the debugging options.
1978 * </ul>
1979 * <code>debugOptions</code> is bitwise OR'd into the current value
1980 *
1981 * @beaninfo
1982 * preferred: true
1983 * enum: NONE_OPTION DebugGraphics.NONE_OPTION
1984 * LOG_OPTION DebugGraphics.LOG_OPTION
1985 * FLASH_OPTION DebugGraphics.FLASH_OPTION
1986 * BUFFERED_OPTION DebugGraphics.BUFFERED_OPTION
1987 * description: Diagnostic options for graphics operations.
1988 */
1989 public void setDebugGraphicsOptions(int debugOptions) {
1990 DebugGraphics.setDebugOptions(this, debugOptions);
1991 }
1992
1993 /** Returns the state of graphics debugging.
1994 *
1995 * @return a bitwise OR'd flag of zero or more of the following options:
1996 * <ul>
1997 * <li>DebugGraphics.LOG_OPTION - causes a text message to be printed.
1998 * <li>DebugGraphics.FLASH_OPTION - causes the drawing to flash several
1999 * times.
2000 * <li>DebugGraphics.BUFFERED_OPTION - creates an
2001 * <code>ExternalWindow</code> that displays the operations
2002 * performed on the View's offscreen buffer.
2003 * <li>DebugGraphics.NONE_OPTION disables debugging.
2004 * <li>A value of 0 causes no changes to the debugging options.
2005 * </ul>
2006 * @see #setDebugGraphicsOptions
2007 */
2008 public int getDebugGraphicsOptions() {
2009 return DebugGraphics.getDebugOptions(this);
2010 }
2011
2012
2013 /**
2014 * Returns true if debug information is enabled for this
2015 * <code>JComponent</code> or one of its parents.
2016 */
2017 int shouldDebugGraphics() {
2018 return DebugGraphics.shouldComponentDebug(this);
2019 }
2020
2021 /**
2022 * This method is now obsolete, please use a combination of
2023 * <code>getActionMap()</code> and <code>getInputMap()</code> for
2024 * similiar behavior. For example, to bind the <code>KeyStroke</code>
2025 * <code>aKeyStroke</code> to the <code>Action</code> <code>anAction</code>
2026 * now use:
2027 * <pre>
2028 * component.getInputMap().put(aKeyStroke, aCommand);
2029 * component.getActionMap().put(aCommmand, anAction);
2030 * </pre>
2031 * The above assumes you want the binding to be applicable for
2032 * <code>WHEN_FOCUSED</code>. To register bindings for other focus
2033 * states use the <code>getInputMap</code> method that takes an integer.
2034 * <p>
2035 * Register a new keyboard action.
2036 * <code>anAction</code> will be invoked if a key event matching
2037 * <code>aKeyStroke</code> occurs and <code>aCondition</code> is verified.
2038 * The <code>KeyStroke</code> object defines a
2039 * particular combination of a keyboard key and one or more modifiers
2040 * (alt, shift, ctrl, meta).
2041 * <p>
2042 * The <code>aCommand</code> will be set in the delivered event if
2043 * specified.
2044 * <p>
2045 * The <code>aCondition</code> can be one of:
2046 * <blockquote>
2047 * <DL>
2048 * <DT>WHEN_FOCUSED
2049 * <DD>The action will be invoked only when the keystroke occurs
2050 * while the component has the focus.
2051 * <DT>WHEN_IN_FOCUSED_WINDOW
2052 * <DD>The action will be invoked when the keystroke occurs while
2053 * the component has the focus or if the component is in the
2054 * window that has the focus. Note that the component need not
2055 * be an immediate descendent of the window -- it can be
2056 * anywhere in the window's containment hierarchy. In other
2057 * words, whenever <em>any</em> component in the window has the focus,
2058 * the action registered with this component is invoked.
2059 * <DT>WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
2060 * <DD>The action will be invoked when the keystroke occurs while the
2061 * component has the focus or if the component is an ancestor of
2062 * the component that has the focus.
2063 * </DL>
2064 * </blockquote>
2065 * <p>
2066 * The combination of keystrokes and conditions lets you define high
2067 * level (semantic) action events for a specified keystroke+modifier
2068 * combination (using the KeyStroke class) and direct to a parent or
2069 * child of a component that has the focus, or to the component itself.
2070 * In other words, in any hierarchical structure of components, an
2071 * arbitrary key-combination can be immediately directed to the
2072 * appropriate component in the hierarchy, and cause a specific method
2073 * to be invoked (usually by way of adapter objects).
2074 * <p>
2075 * If an action has already been registered for the receiving
2076 * container, with the same charCode and the same modifiers,
2077 * <code>anAction</code> will replace the action.
2078 *
2079 * @param anAction the <code>Action</code> to be registered
2080 * @param aCommand the command to be set in the delivered event
2081 * @param aKeyStroke the <code>KeyStroke</code> to bind to the action
2082 * @param aCondition the condition that needs to be met, see above
2083 * @see KeyStroke
2084 */
2085 public void registerKeyboardAction(ActionListener anAction,String aCommand,KeyStroke aKeyStroke,int aCondition) {
2086
2087 InputMap inputMap = getInputMap(aCondition, true);
2088
2089 if (inputMap != null) {
2090 ActionMap actionMap = getActionMap(true);
2091 ActionStandin action = new ActionStandin(anAction, aCommand);
2092 inputMap.put(aKeyStroke, action);
2093 if (actionMap != null) {
2094 actionMap.put(action, action);
2095 }
2096 }
2097 }
2098
2099 /**
2100 * Registers any bound <code>WHEN_IN_FOCUSED_WINDOW</code> actions with
2101 * the <code>KeyboardManager</code>. If <code>onlyIfNew</code>
2102 * is true only actions that haven't been registered are pushed
2103 * to the <code>KeyboardManager</code>;
2104 * otherwise all actions are pushed to the <code>KeyboardManager</code>.
2105 *
2106 * @param onlyIfNew if true, only actions that haven't been registered
2107 * are pushed to the <code>KeyboardManager</code>
2108 */
2109 private void registerWithKeyboardManager(boolean onlyIfNew) {
2110 InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW, false);
2111 KeyStroke[] strokes;
2112 Hashtable<KeyStroke, KeyStroke> registered = (Hashtable)getClientProperty
2113 (WHEN_IN_FOCUSED_WINDOW_BINDINGS);
2114
2115 if (inputMap != null) {
2116 // Push any new KeyStrokes to the KeyboardManager.
2117 strokes = inputMap.allKeys();
2118 if (strokes != null) {
2119 for (int counter = strokes.length - 1; counter >= 0;
2120 counter--) {
2121 if (!onlyIfNew || registered == null ||
2122 registered.get(strokes[counter]) == null) {
2123 registerWithKeyboardManager(strokes[counter]);
2124 }
2125 if (registered != null) {
2126 registered.remove(strokes[counter]);
2127 }
2128 }
2129 }
2130 }
2131 else {
2132 strokes = null;
2133 }
2134 // Remove any old ones.
2135 if (registered != null && registered.size() > 0) {
2136 Enumeration<KeyStroke> keys = registered.keys();
2137
2138 while (keys.hasMoreElements()) {
2139 KeyStroke ks = keys.nextElement();
2140 unregisterWithKeyboardManager(ks);
2141 }
2142 registered.clear();
2143 }
2144 // Updated the registered Hashtable.
2145 if (strokes != null && strokes.length > 0) {
2146 if (registered == null) {
2147 registered = new Hashtable<KeyStroke, KeyStroke>(strokes.length);
2148 putClientProperty(WHEN_IN_FOCUSED_WINDOW_BINDINGS, registered);
2149 }
2150 for (int counter = strokes.length - 1; counter >= 0; counter--) {
2151 registered.put(strokes[counter], strokes[counter]);
2152 }
2153 }
2154 else {
2155 putClientProperty(WHEN_IN_FOCUSED_WINDOW_BINDINGS, null);
2156 }
2157 }
2158
2159 /**
2160 * Unregisters all the previously registered
2161 * <code>WHEN_IN_FOCUSED_WINDOW</code> <code>KeyStroke</code> bindings.
2162 */
2163 private void unregisterWithKeyboardManager() {
2164 Hashtable registered = (Hashtable)getClientProperty
2165 (WHEN_IN_FOCUSED_WINDOW_BINDINGS);
2166
2167 if (registered != null && registered.size() > 0) {
2168 Enumeration keys = registered.keys();
2169
2170 while (keys.hasMoreElements()) {
2171 KeyStroke ks = (KeyStroke)keys.nextElement();
2172 unregisterWithKeyboardManager(ks);
2173 }
2174 }
2175 putClientProperty(WHEN_IN_FOCUSED_WINDOW_BINDINGS, null);
2176 }
2177
2178 /**
2179 * Invoked from <code>ComponentInputMap</code> when its bindings change.
2180 * If <code>inputMap</code> is the current <code>windowInputMap</code>
2181 * (or a parent of the window <code>InputMap</code>)
2182 * the <code>KeyboardManager</code> is notified of the new bindings.
2183 *
2184 * @param inputMap the map containing the new bindings
2185 */
2186 void componentInputMapChanged(ComponentInputMap inputMap) {
2187 InputMap km = getInputMap(WHEN_IN_FOCUSED_WINDOW, false);
2188
2189 while (km != inputMap && km != null) {
2190 km = km.getParent();
2191 }
2192 if (km != null) {
2193 registerWithKeyboardManager(false);
2194 }
2195 }
2196
2197 private void registerWithKeyboardManager(KeyStroke aKeyStroke) {
2198 KeyboardManager.getCurrentManager().registerKeyStroke(aKeyStroke,this);
2199 }
2200
2201 private void unregisterWithKeyboardManager(KeyStroke aKeyStroke) {
2202 KeyboardManager.getCurrentManager().unregisterKeyStroke(aKeyStroke,
2203 this);
2204 }
2205
2206 /**
2207 * This method is now obsolete, please use a combination of
2208 * <code>getActionMap()</code> and <code>getInputMap()</code> for
2209 * similiar behavior.
2210 */
2211 public void registerKeyboardAction(ActionListener anAction,KeyStroke aKeyStroke,int aCondition) {
2212 registerKeyboardAction(anAction,null,aKeyStroke,aCondition);
2213 }
2214
2215 /**
2216 * This method is now obsolete. To unregister an existing binding
2217 * you can either remove the binding from the
2218 * <code>ActionMap/InputMap</code>, or place a dummy binding the
2219 * <code>InputMap</code>. Removing the binding from the
2220 * <code>InputMap</code> allows bindings in parent <code>InputMap</code>s
2221 * to be active, whereas putting a dummy binding in the
2222 * <code>InputMap</code> effectively disables
2223 * the binding from ever happening.
2224 * <p>
2225 * Unregisters a keyboard action.
2226 * This will remove the binding from the <code>ActionMap</code>
2227 * (if it exists) as well as the <code>InputMap</code>s.
2228 */
2229 public void unregisterKeyboardAction(KeyStroke aKeyStroke) {
2230 ActionMap am = getActionMap(false);
2231 for (int counter = 0; counter < 3; counter++) {
2232 InputMap km = getInputMap(counter, false);
2233 if (km != null) {
2234 Object actionID = km.get(aKeyStroke);
2235
2236 if (am != null && actionID != null) {
2237 am.remove(actionID);
2238 }
2239 km.remove(aKeyStroke);
2240 }
2241 }
2242 }
2243
2244 /**
2245 * Returns the <code>KeyStrokes</code> that will initiate
2246 * registered actions.
2247 *
2248 * @return an array of <code>KeyStroke</code> objects
2249 * @see #registerKeyboardAction
2250 */
2251 public KeyStroke[] getRegisteredKeyStrokes() {
2252 int[] counts = new int[3];
2253 KeyStroke[][] strokes = new KeyStroke[3][];
2254
2255 for (int counter = 0; counter < 3; counter++) {
2256 InputMap km = getInputMap(counter, false);
2257 strokes[counter] = (km != null) ? km.allKeys() : null;
2258 counts[counter] = (strokes[counter] != null) ?
2259 strokes[counter].length : 0;
2260 }
2261 KeyStroke[] retValue = new KeyStroke[counts[0] + counts[1] +
2262 counts[2]];
2263 for (int counter = 0, last = 0; counter < 3; counter++) {
2264 if (counts[counter] > 0) {
2265 System.arraycopy(strokes[counter], 0, retValue, last,
2266 counts[counter]);
2267 last += counts[counter];
2268 }
2269 }
2270 return retValue;
2271 }
2272
2273 /**
2274 * Returns the condition that determines whether a registered action
2275 * occurs in response to the specified keystroke.
2276 * <p>
2277 * For Java 2 platform v1.3, a <code>KeyStroke</code> can be associated
2278 * with more than one condition.
2279 * For example, 'a' could be bound for the two
2280 * conditions <code>WHEN_FOCUSED</code> and
2281 * <code>WHEN_IN_FOCUSED_WINDOW</code> condition.
2282 *
2283 * @return the action-keystroke condition
2284 */
2285 public int getConditionForKeyStroke(KeyStroke aKeyStroke) {
2286 for (int counter = 0; counter < 3; counter++) {
2287 InputMap inputMap = getInputMap(counter, false);
2288 if (inputMap != null && inputMap.get(aKeyStroke) != null) {
2289 return counter;
2290 }
2291 }
2292 return UNDEFINED_CONDITION;
2293 }
2294
2295 /**
2296 * Returns the object that will perform the action registered for a
2297 * given keystroke.
2298 *
2299 * @return the <code>ActionListener</code>
2300 * object invoked when the keystroke occurs
2301 */
2302 public ActionListener getActionForKeyStroke(KeyStroke aKeyStroke) {
2303 ActionMap am = getActionMap(false);
2304
2305 if (am == null) {
2306 return null;
2307 }
2308 for (int counter = 0; counter < 3; counter++) {
2309 InputMap inputMap = getInputMap(counter, false);
2310 if (inputMap != null) {
2311 Object actionBinding = inputMap.get(aKeyStroke);
2312
2313 if (actionBinding != null) {
2314 Action action = am.get(actionBinding);
2315 if (action instanceof ActionStandin) {
2316 return ((ActionStandin)action).actionListener;
2317 }
2318 return action;
2319 }
2320 }
2321 }
2322 return null;
2323 }
2324
2325 /**
2326 * Unregisters all the bindings in the first tier <code>InputMaps</code>
2327 * and <code>ActionMap</code>. This has the effect of removing any
2328 * local bindings, and allowing the bindings defined in parent
2329 * <code>InputMap/ActionMaps</code>
2330 * (the UI is usually defined in the second tier) to persist.
2331 */
2332 public void resetKeyboardActions() {
2333 // Keys
2334 for (int counter = 0; counter < 3; counter++) {
2335 InputMap inputMap = getInputMap(counter, false);
2336
2337 if (inputMap != null) {
2338 inputMap.clear();
2339 }
2340 }
2341
2342 // Actions
2343 ActionMap am = getActionMap(false);
2344
2345 if (am != null) {
2346 am.clear();
2347 }
2348 }
2349
2350 /**
2351 * Sets the <code>InputMap</code> to use under the condition
2352 * <code>condition</code> to
2353 * <code>map</code>. A <code>null</code> value implies you
2354 * do not want any bindings to be used, even from the UI. This will
2355 * not reinstall the UI <code>InputMap</code> (if there was one).
2356 * <code>condition</code> has one of the following values:
2357 * <ul>
2358 * <li><code>WHEN_IN_FOCUSED_WINDOW</code>
2359 * <li><code>WHEN_FOCUSED</code>
2360 * <li><code>WHEN_ANCESTOR_OF_FOCUSED_COMPONENT</code>
2361 * </ul>
2362 * If <code>condition</code> is <code>WHEN_IN_FOCUSED_WINDOW</code>
2363 * and <code>map</code> is not a <code>ComponentInputMap</code>, an
2364 * <code>IllegalArgumentException</code> will be thrown.
2365 * Similarly, if <code>condition</code> is not one of the values
2366 * listed, an <code>IllegalArgumentException</code> will be thrown.
2367 *
2368 * @param condition one of the values listed above
2369 * @param map the <code>InputMap</code> to use for the given condition
2370 * @exception IllegalArgumentException if <code>condition</code> is
2371 * <code>WHEN_IN_FOCUSED_WINDOW</code> and <code>map</code>
2372 * is not an instance of <code>ComponentInputMap</code>; or
2373 * if <code>condition</code> is not one of the legal values
2374 * specified above
2375 * @since 1.3
2376 */
2377 public final void setInputMap(int condition, InputMap map) {
2378 switch (condition) {
2379 case WHEN_IN_FOCUSED_WINDOW:
2380 if (map != null && !(map instanceof ComponentInputMap)) {
2381 throw new IllegalArgumentException("WHEN_IN_FOCUSED_WINDOW InputMaps must be of type ComponentInputMap");
2382 }
2383 windowInputMap = (ComponentInputMap)map;
2384 setFlag(WIF_INPUTMAP_CREATED, true);
2385 registerWithKeyboardManager(false);
2386 break;
2387 case WHEN_ANCESTOR_OF_FOCUSED_COMPONENT:
2388 ancestorInputMap = map;
2389 setFlag(ANCESTOR_INPUTMAP_CREATED, true);
2390 break;
2391 case WHEN_FOCUSED:
2392 focusInputMap = map;
2393 setFlag(FOCUS_INPUTMAP_CREATED, true);
2394 break;
2395 default:
2396 throw new IllegalArgumentException("condition must be one of JComponent.WHEN_IN_FOCUSED_WINDOW, JComponent.WHEN_FOCUSED or JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT");
2397 }
2398 }
2399
2400 /**
2401 * Returns the <code>InputMap</code> that is used during
2402 * <code>condition</code>.
2403 *
2404 * @param condition one of WHEN_IN_FOCUSED_WINDOW, WHEN_FOCUSED,
2405 * WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
2406 * @return the <code>InputMap</code> for the specified
2407 * <code>condition</code>
2408 * @since 1.3
2409 */
2410 public final InputMap getInputMap(int condition) {
2411 return getInputMap(condition, true);
2412 }
2413
2414 /**
2415 * Returns the <code>InputMap</code> that is used when the
2416 * component has focus.
2417 * This is convenience method for <code>getInputMap(WHEN_FOCUSED)</code>.
2418 *
2419 * @return the <code>InputMap</code> used when the component has focus
2420 * @since 1.3
2421 */
2422 public final InputMap getInputMap() {
2423 return getInputMap(WHEN_FOCUSED, true);
2424 }
2425
2426 /**
2427 * Sets the <code>ActionMap</code> to <code>am</code>. This does not set
2428 * the parent of the <code>am</code> to be the <code>ActionMap</code>
2429 * from the UI (if there was one), it is up to the caller to have done this.
2430 *
2431 * @param am the new <code>ActionMap</code>
2432 * @since 1.3
2433 */
2434 public final void setActionMap(ActionMap am) {
2435 actionMap = am;
2436 setFlag(ACTIONMAP_CREATED, true);
2437 }
2438
2439 /**
2440 * Returns the <code>ActionMap</code> used to determine what
2441 * <code>Action</code> to fire for particular <code>KeyStroke</code>
2442 * binding. The returned <code>ActionMap</code>, unless otherwise
2443 * set, will have the <code>ActionMap</code> from the UI set as the parent.
2444 *
2445 * @return the <code>ActionMap</code> containing the key/action bindings
2446 * @since 1.3
2447 */
2448 public final ActionMap getActionMap() {
2449 return getActionMap(true);
2450 }
2451
2452 /**
2453 * Returns the <code>InputMap</code> to use for condition
2454 * <code>condition</code>. If the <code>InputMap</code> hasn't
2455 * been created, and <code>create</code> is
2456 * true, it will be created.
2457 *
2458 * @param condition one of the following values:
2459 * <ul>
2460 * <li>JComponent.FOCUS_INPUTMAP_CREATED
2461 * <li>JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
2462 * <li>JComponent.WHEN_IN_FOCUSED_WINDOW
2463 * </ul>
2464 * @param create if true, create the <code>InputMap</code> if it
2465 * is not already created
2466 * @return the <code>InputMap</code> for the given <code>condition</code>;
2467 * if <code>create</code> is false and the <code>InputMap</code>
2468 * hasn't been created, returns <code>null</code>
2469 * @exception IllegalArgumentException if <code>condition</code>
2470 * is not one of the legal values listed above
2471 */
2472 final InputMap getInputMap(int condition, boolean create) {
2473 switch (condition) {
2474 case WHEN_FOCUSED:
2475 if (getFlag(FOCUS_INPUTMAP_CREATED)) {
2476 return focusInputMap;
2477 }
2478 // Hasn't been created yet.
2479 if (create) {
2480 InputMap km = new InputMap();
2481 setInputMap(condition, km);
2482 return km;
2483 }
2484 break;
2485 case WHEN_ANCESTOR_OF_FOCUSED_COMPONENT:
2486 if (getFlag(ANCESTOR_INPUTMAP_CREATED)) {
2487 return ancestorInputMap;
2488 }
2489 // Hasn't been created yet.
2490 if (create) {
2491 InputMap km = new InputMap();
2492 setInputMap(condition, km);
2493 return km;
2494 }
2495 break;
2496 case WHEN_IN_FOCUSED_WINDOW:
2497 if (getFlag(WIF_INPUTMAP_CREATED)) {
2498 return windowInputMap;
2499 }
2500 // Hasn't been created yet.
2501 if (create) {
2502 ComponentInputMap km = new ComponentInputMap(this);
2503 setInputMap(condition, km);
2504 return km;
2505 }
2506 break;
2507 default:
2508 throw new IllegalArgumentException("condition must be one of JComponent.WHEN_IN_FOCUSED_WINDOW, JComponent.WHEN_FOCUSED or JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT");
2509 }
2510 return null;
2511 }
2512
2513 /**
2514 * Finds and returns the appropriate <code>ActionMap</code>.
2515 *
2516 * @param create if true, create the <code>ActionMap</code> if it
2517 * is not already created
2518 * @return the <code>ActionMap</code> for this component; if the
2519 * <code>create</code> flag is false and there is no
2520 * current <code>ActionMap</code>, returns <code>null</code>
2521 */
2522 final ActionMap getActionMap(boolean create) {
2523 if (getFlag(ACTIONMAP_CREATED)) {
2524 return actionMap;
2525 }
2526 // Hasn't been created.
2527 if (create) {
2528 ActionMap am = new ActionMap();
2529 setActionMap(am);
2530 return am;
2531 }
2532 return null;
2533 }
2534
2535 /**
2536 * Returns the baseline. The baseline is measured from the top of
2537 * the component. This method is primarily meant for
2538 * <code>LayoutManager</code>s to align components along their
2539 * baseline. A return value less than 0 indicates this component
2540 * does not have a reasonable baseline and that
2541 * <code>LayoutManager</code>s should not align this component on
2542 * its baseline.
2543 * <p>
2544 * This method calls into the <code>ComponentUI</code> method of the
2545 * same name. If this component does not have a <code>ComponentUI</code>
2546 * -1 will be returned. If a value >= 0 is
2547 * returned, then the component has a valid baseline for any
2548 * size >= the minimum size and <code>getBaselineResizeBehavior</code>
2549 * can be used to determine how the baseline changes with size.
2550 *
2551 * @throws IllegalArgumentException {@inheritDoc}
2552 * @see #getBaselineResizeBehavior
2553 * @see java.awt.FontMetrics
2554 * @since 1.6
2555 */
2556 public int getBaseline(int width, int height) {
2557 // check size.
2558 super.getBaseline(width, height);
2559 if (ui != null) {
2560 return ui.getBaseline(this, width, height);
2561 }
2562 return -1;
2563 }
2564
2565 /**
2566 * Returns an enum indicating how the baseline of the component
2567 * changes as the size changes. This method is primarily meant for
2568 * layout managers and GUI builders.
2569 * <p>
2570 * This method calls into the <code>ComponentUI</code> method of
2571 * the same name. If this component does not have a
2572 * <code>ComponentUI</code>
2573 * <code>BaselineResizeBehavior.OTHER</code> will be
2574 * returned. Subclasses should
2575 * never return <code>null</code>; if the baseline can not be
2576 * calculated return <code>BaselineResizeBehavior.OTHER</code>. Callers
2577 * should first ask for the baseline using
2578 * <code>getBaseline</code> and if a value >= 0 is returned use
2579 * this method. It is acceptable for this method to return a
2580 * value other than <code>BaselineResizeBehavior.OTHER</code> even if
2581 * <code>getBaseline</code> returns a value less than 0.
2582 *
2583 * @see #getBaseline(int, int)
2584 * @since 1.6
2585 */
2586 public BaselineResizeBehavior getBaselineResizeBehavior() {
2587 if (ui != null) {
2588 return ui.getBaselineResizeBehavior(this);
2589 }
2590 return BaselineResizeBehavior.OTHER;
2591 }
2592
2593 /**
2594 * In release 1.4, the focus subsystem was rearchitected.
2595 * For more information, see
2596 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
2597 * How to Use the Focus Subsystem</a>,
2598 * a section in <em>The Java Tutorial</em>.
2599 * <p>
2600 * Requests focus on this <code>JComponent</code>'s
2601 * <code>FocusTraversalPolicy</code>'s default <code>Component</code>.
2602 * If this <code>JComponent</code> is a focus cycle root, then its
2603 * <code>FocusTraversalPolicy</code> is used. Otherwise, the
2604 * <code>FocusTraversalPolicy</code> of this <code>JComponent</code>'s
2605 * focus-cycle-root ancestor is used.
2606 *
2607 * @see java.awt.FocusTraversalPolicy#getDefaultComponent
2608 * @deprecated As of 1.4, replaced by
2609 * <code>FocusTraversalPolicy.getDefaultComponent(Container).requestFocus()</code>
2610 */
2611 @Deprecated
2612 public boolean requestDefaultFocus() {
2613 Container nearestRoot =
2614 (isFocusCycleRoot()) ? this : getFocusCycleRootAncestor();
2615 if (nearestRoot == null) {
2616 return false;
2617 }
2618 Component comp = nearestRoot.getFocusTraversalPolicy().
2619 getDefaultComponent(nearestRoot);
2620 if (comp != null) {
2621 comp.requestFocus();
2622 return true;
2623 } else {
2624 return false;
2625 }
2626 }
2627
2628 /**
2629 * Makes the component visible or invisible.
2630 * Overrides <code>Component.setVisible</code>.
2631 *
2632 * @param aFlag true to make the component visible; false to
2633 * make it invisible
2634 *
2635 * @beaninfo
2636 * attribute: visualUpdate true
2637 */
2638 public void setVisible(boolean aFlag) {
2639 if(aFlag != isVisible()) {
2640 super.setVisible(aFlag);
2641 Container parent = getParent();
2642 if(parent != null) {
2643 Rectangle r = getBounds();
2644 parent.repaint(r.x,r.y,r.width,r.height);
2645 }
2646 // Some (all should) LayoutManagers do not consider components
2647 // that are not visible. As such we need to revalidate when the
2648 // visible bit changes.
2649 revalidate();
2650 }
2651 }
2652
2653 /**
2654 * Sets whether or not this component is enabled.
2655 * A component that is enabled may respond to user input,
2656 * while a component that is not enabled cannot respond to
2657 * user input. Some components may alter their visual
2658 * representation when they are disabled in order to
2659 * provide feedback to the user that they cannot take input.
2660 * <p>Note: Disabling a component does not disable its children.
2661 *
2662 * <p>Note: Disabling a lightweight component does not prevent it from
2663 * receiving MouseEvents.
2664 *
2665 * @param enabled true if this component should be enabled, false otherwise
2666 * @see java.awt.Component#isEnabled
2667 * @see java.awt.Component#isLightweight
2668 *
2669 * @beaninfo
2670 * preferred: true
2671 * bound: true
2672 * attribute: visualUpdate true
2673 * description: The enabled state of the component.
2674 */
2675 public void setEnabled(boolean enabled) {
2676 boolean oldEnabled = isEnabled();
2677 super.setEnabled(enabled);
2678 firePropertyChange("enabled", oldEnabled, enabled);
2679 if (enabled != oldEnabled) {
2680 repaint();
2681 }
2682 }
2683
2684 /**
2685 * Sets the foreground color of this component. It is up to the
2686 * look and feel to honor this property, some may choose to ignore
2687 * it.
2688 *
2689 * @param fg the desired foreground <code>Color</code>
2690 * @see java.awt.Component#getForeground
2691 *
2692 * @beaninfo
2693 * preferred: true
2694 * bound: true
2695 * attribute: visualUpdate true
2696 * description: The foreground color of the component.
2697 */
2698 public void setForeground(Color fg) {
2699 Color oldFg = getForeground();
2700 super.setForeground(fg);
2701 if ((oldFg != null) ? !oldFg.equals(fg) : ((fg != null) && !fg.equals(oldFg))) {
2702 // foreground already bound in AWT1.2
2703 repaint();
2704 }
2705 }
2706
2707 /**
2708 * Sets the background color of this component. The background
2709 * color is used only if the component is opaque, and only
2710 * by subclasses of <code>JComponent</code> or
2711 * <code>ComponentUI</code> implementations. Direct subclasses of
2712 * <code>JComponent</code> must override
2713 * <code>paintComponent</code> to honor this property.
2714 * <p>
2715 * It is up to the look and feel to honor this property, some may
2716 * choose to ignore it.
2717 *
2718 * @param bg the desired background <code>Color</code>
2719 * @see java.awt.Component#getBackground
2720 * @see #setOpaque
2721 *
2722 * @beaninfo
2723 * preferred: true
2724 * bound: true
2725 * attribute: visualUpdate true
2726 * description: The background color of the component.
2727 */
2728 public void setBackground(Color bg) {
2729 Color oldBg = getBackground();
2730 super.setBackground(bg);
2731 if ((oldBg != null) ? !oldBg.equals(bg) : ((bg != null) && !bg.equals(oldBg))) {
2732 // background already bound in AWT1.2
2733 repaint();
2734 }
2735 }
2736
2737 /**
2738 * Sets the font for this component.
2739 *
2740 * @param font the desired <code>Font</code> for this component
2741 * @see java.awt.Component#getFont
2742 *
2743 * @beaninfo
2744 * preferred: true
2745 * bound: true
2746 * attribute: visualUpdate true
2747 * description: The font for the component.
2748 */
2749 public void setFont(Font font) {
2750 Font oldFont = getFont();
2751 super.setFont(font);
2752 // font already bound in AWT1.2
2753 if (font != oldFont) {
2754 revalidate();
2755 repaint();
2756 }
2757 }
2758
2759 /**
2760 * Returns the default locale used to initialize each JComponent's
2761 * locale property upon creation.
2762 *
2763 * The default locale has "AppContext" scope so that applets (and
2764 * potentially multiple lightweight applications running in a single VM)
2765 * can have their own setting. An applet can safely alter its default
2766 * locale because it will have no affect on other applets (or the browser).
2767 *
2768 * @return the default <code>Locale</code>.
2769 * @see #setDefaultLocale
2770 * @see java.awt.Component#getLocale
2771 * @see #setLocale
2772 * @since 1.4
2773 */
2774 static public Locale getDefaultLocale() {
2775 Locale l = (Locale) SwingUtilities.appContextGet(defaultLocale);
2776 if( l == null ) {
2777 //REMIND(bcb) choosing the default value is more complicated
2778 //than this.
2779 l = Locale.getDefault();
2780 JComponent.setDefaultLocale( l );
2781 }
2782 return l;
2783 }
2784
2785
2786 /**
2787 * Sets the default locale used to initialize each JComponent's locale
2788 * property upon creation. The initial value is the VM's default locale.
2789 *
2790 * The default locale has "AppContext" scope so that applets (and
2791 * potentially multiple lightweight applications running in a single VM)
2792 * can have their own setting. An applet can safely alter its default
2793 * locale because it will have no affect on other applets (or the browser).
2794 *
2795 * @param l the desired default <code>Locale</code> for new components.
2796 * @see #getDefaultLocale
2797 * @see java.awt.Component#getLocale
2798 * @see #setLocale
2799 * @since 1.4
2800 */
2801 static public void setDefaultLocale( Locale l ) {
2802 SwingUtilities.appContextPut(defaultLocale, l);
2803 }
2804
2805
2806 /**
2807 * Processes any key events that the component itself
2808 * recognizes. This is called after the focus
2809 * manager and any interested listeners have been
2810 * given a chance to steal away the event. This
2811 * method is called only if the event has not
2812 * yet been consumed. This method is called prior
2813 * to the keyboard UI logic.
2814 * <p>
2815 * This method is implemented to do nothing. Subclasses would
2816 * normally override this method if they process some
2817 * key events themselves. If the event is processed,
2818 * it should be consumed.
2819 */
2820 protected void processComponentKeyEvent(KeyEvent e) {
2821 }
2822
2823 /** Overrides <code>processKeyEvent</code> to process events. **/
2824 protected void processKeyEvent(KeyEvent e) {
2825 boolean result;
2826 boolean shouldProcessKey;
2827
2828 // This gives the key event listeners a crack at the event
2829 super.processKeyEvent(e);
2830
2831 // give the component itself a crack at the event
2832 if (! e.isConsumed()) {
2833 processComponentKeyEvent(e);
2834 }
2835
2836 shouldProcessKey = KeyboardState.shouldProcess(e);
2837
2838 if(e.isConsumed()) {
2839 return;
2840 }
2841
2842 if (shouldProcessKey && processKeyBindings(e, e.getID() ==
2843 KeyEvent.KEY_PRESSED)) {
2844 e.consume();
2845 }
2846 }
2847
2848 /**
2849 * Invoked to process the key bindings for <code>ks</code> as the result
2850 * of the <code>KeyEvent</code> <code>e</code>. This obtains
2851 * the appropriate <code>InputMap</code>,
2852 * gets the binding, gets the action from the <code>ActionMap</code>,
2853 * and then (if the action is found and the component
2854 * is enabled) invokes <code>notifyAction</code> to notify the action.
2855 *
2856 * @param ks the <code>KeyStroke</code> queried
2857 * @param e the <code>KeyEvent</code>
2858 * @param condition one of the following values:
2859 * <ul>
2860 * <li>JComponent.WHEN_FOCUSED
2861 * <li>JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
2862 * <li>JComponent.WHEN_IN_FOCUSED_WINDOW
2863 * </ul>
2864 * @param pressed true if the key is pressed
2865 * @return true if there was a binding to an action, and the action
2866 * was enabled
2867 *
2868 * @since 1.3
2869 */
2870 protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
2871 int condition, boolean pressed) {
2872 InputMap map = getInputMap(condition, false);
2873 ActionMap am = getActionMap(false);
2874
2875 if(map != null && am != null && isEnabled()) {
2876 Object binding = map.get(ks);
2877 Action action = (binding == null) ? null : am.get(binding);
2878 if (action != null) {
2879 return SwingUtilities.notifyAction(action, ks, e, this,
2880 e.getModifiers());
2881 }
2882 }
2883 return false;
2884 }
2885
2886 /**
2887 * This is invoked as the result of a <code>KeyEvent</code>
2888 * that was not consumed by the <code>FocusManager</code>,
2889 * <code>KeyListeners</code>, or the component. It will first try
2890 * <code>WHEN_FOCUSED</code> bindings,
2891 * then <code>WHEN_ANCESTOR_OF_FOCUSED_COMPONENT</code> bindings,
2892 * and finally <code>WHEN_IN_FOCUSED_WINDOW</code> bindings.
2893 *
2894 * @param e the unconsumed <code>KeyEvent</code>
2895 * @param pressed true if the key is pressed
2896 * @return true if there is a key binding for <code>e</code>
2897 */
2898 boolean processKeyBindings(KeyEvent e, boolean pressed) {
2899 if (!SwingUtilities.isValidKeyEventForKeyBindings(e)) {
2900 return false;
2901 }
2902 // Get the KeyStroke
2903 // There may be two keystrokes associated with a low-level key event;
2904 // in this case a keystroke made of an extended key code has a priority.
2905 KeyStroke ks;
2906 KeyStroke ksE = null;
2907
2908 if (e.getID() == KeyEvent.KEY_TYPED) {
2909 ks = KeyStroke.getKeyStroke(e.getKeyChar());
2910 }
2911 else {
2912 ks = KeyStroke.getKeyStroke(e.getKeyCode(),e.getModifiers(),
2913 (pressed ? false:true));
2914 if (e.getKeyCode() != e.getExtendedKeyCode()) {
2915 ksE = KeyStroke.getKeyStroke(e.getExtendedKeyCode(),e.getModifiers(),
2916 (pressed ? false:true));
2917 }
2918 }
2919
2920 // Do we have a key binding for e?
2921 // If we have a binding by an extended code, use it.
2922 // If not, check for regular code binding.
2923 if(ksE != null && processKeyBinding(ksE, e, WHEN_FOCUSED, pressed)) {
2924 return true;
2925 }
2926 if(processKeyBinding(ks, e, WHEN_FOCUSED, pressed))
2927 return true;
2928
2929 /* We have no key binding. Let's try the path from our parent to the
2930 * window excluded. We store the path components so we can avoid
2931 * asking the same component twice.
2932 */
2933 Container parent = this;
2934 while (parent != null && !(parent instanceof Window) &&
2935 !(parent instanceof Applet)) {
2936 if(parent instanceof JComponent) {
2937 if(ksE != null && ((JComponent)parent).processKeyBinding(ksE, e,
2938 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, pressed))
2939 return true;
2940 if(((JComponent)parent).processKeyBinding(ks, e,
2941 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, pressed))
2942 return true;
2943 }
2944 // This is done so that the children of a JInternalFrame are
2945 // given precedence for WHEN_IN_FOCUSED_WINDOW bindings before
2946 // other components WHEN_IN_FOCUSED_WINDOW bindings. This also gives
2947 // more precedence to the WHEN_IN_FOCUSED_WINDOW bindings of the
2948 // JInternalFrame's children vs the
2949 // WHEN_ANCESTOR_OF_FOCUSED_COMPONENT bindings of the parents.
2950 // maybe generalize from JInternalFrame (like isFocusCycleRoot).
2951 if ((parent instanceof JInternalFrame) &&
2952 JComponent.processKeyBindingsForAllComponents(e,parent,pressed)){
2953 return true;
2954 }
2955 parent = parent.getParent();
2956 }
2957
2958 /* No components between the focused component and the window is
2959 * actually interested by the key event. Let's try the other
2960 * JComponent in this window.
2961 */
2962 if(parent != null) {
2963 return JComponent.processKeyBindingsForAllComponents(e,parent,pressed);
2964 }
2965 return false;
2966 }
2967
2968 static boolean processKeyBindingsForAllComponents(KeyEvent e,
2969 Container container, boolean pressed) {
2970 while (true) {
2971 if (KeyboardManager.getCurrentManager().fireKeyboardAction(
2972 e, pressed, container)) {
2973 return true;
2974 }
2975 if (container instanceof Popup.HeavyWeightWindow) {
2976 container = ((Window)container).getOwner();
2977 }
2978 else {
2979 return false;
2980 }
2981 }
2982 }
2983
2984 /**
2985 * Registers the text to display in a tool tip.
2986 * The text displays when the cursor lingers over the component.
2987 * <p>
2988 * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/tooltip.html">How to Use Tool Tips</a>
2989 * in <em>The Java Tutorial</em>
2990 * for further documentation.
2991 *
2992 * @param text the string to display; if the text is <code>null</code>,
2993 * the tool tip is turned off for this component
2994 * @see #TOOL_TIP_TEXT_KEY
2995 * @beaninfo
2996 * preferred: true
2997 * description: The text to display in a tool tip.
2998 */
2999 public void setToolTipText(String text) {
3000 String oldText = getToolTipText();
3001 putClientProperty(TOOL_TIP_TEXT_KEY, text);
3002 ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
3003 if (text != null) {
3004 if (oldText == null) {
3005 toolTipManager.registerComponent(this);
3006 }
3007 } else {
3008 toolTipManager.unregisterComponent(this);
3009 }
3010 }
3011
3012 /**
3013 * Returns the tooltip string that has been set with
3014 * <code>setToolTipText</code>.
3015 *
3016 * @return the text of the tool tip
3017 * @see #TOOL_TIP_TEXT_KEY
3018 */
3019 public String getToolTipText() {
3020 return (String)getClientProperty(TOOL_TIP_TEXT_KEY);
3021 }
3022
3023
3024 /**
3025 * Returns the string to be used as the tooltip for <i>event</i>.
3026 * By default this returns any string set using
3027 * <code>setToolTipText</code>. If a component provides
3028 * more extensive API to support differing tooltips at different locations,
3029 * this method should be overridden.
3030 */
3031 public String getToolTipText(MouseEvent event) {
3032 return getToolTipText();
3033 }
3034
3035 /**
3036 * Returns the tooltip location in this component's coordinate system.
3037 * If <code>null</code> is returned, Swing will choose a location.
3038 * The default implementation returns <code>null</code>.
3039 *
3040 * @param event the <code>MouseEvent</code> that caused the
3041 * <code>ToolTipManager</code> to show the tooltip
3042 * @return always returns <code>null</code>
3043 */
3044 public Point getToolTipLocation(MouseEvent event) {
3045 return null;
3046 }
3047
3048 /**
3049 * Returns the preferred location to display the popup menu in this
3050 * component's coordinate system. It is up to the look and feel to
3051 * honor this property, some may choose to ignore it.
3052 * If {@code null}, the look and feel will choose a suitable location.
3053 *
3054 * @param event the {@code MouseEvent} that triggered the popup to be
3055 * shown, or {@code null} if the popup is not being shown as the
3056 * result of a mouse event
3057 * @return location to display the {@code JPopupMenu}, or {@code null}
3058 * @since 1.5
3059 */
3060 public Point getPopupLocation(MouseEvent event) {
3061 return null;
3062 }
3063
3064
3065 /**
3066 * Returns the instance of <code>JToolTip</code> that should be used
3067 * to display the tooltip.
3068 * Components typically would not override this method,
3069 * but it can be used to
3070 * cause different tooltips to be displayed differently.
3071 *
3072 * @return the <code>JToolTip</code> used to display this toolTip
3073 */
3074 public JToolTip createToolTip() {
3075 JToolTip tip = new JToolTip();
3076 tip.setComponent(this);
3077 return tip;
3078 }
3079
3080 /**
3081 * Forwards the <code>scrollRectToVisible()</code> message to the
3082 * <code>JComponent</code>'s parent. Components that can service
3083 * the request, such as <code>JViewport</code>,
3084 * override this method and perform the scrolling.
3085 *
3086 * @param aRect the visible <code>Rectangle</code>
3087 * @see JViewport
3088 */
3089 public void scrollRectToVisible(Rectangle aRect) {
3090 Container parent;
3091 int dx = getX(), dy = getY();
3092
3093 for (parent = getParent();
3094 !(parent == null) &&
3095 !(parent instanceof JComponent) &&
3096 !(parent instanceof CellRendererPane);
3097 parent = parent.getParent()) {
3098 Rectangle bounds = parent.getBounds();
3099
3100 dx += bounds.x;
3101 dy += bounds.y;
3102 }
3103
3104 if (!(parent == null) && !(parent instanceof CellRendererPane)) {
3105 aRect.x += dx;
3106 aRect.y += dy;
3107
3108 ((JComponent)parent).scrollRectToVisible(aRect);
3109 aRect.x -= dx;
3110 aRect.y -= dy;
3111 }
3112 }
3113
3114 /**
3115 * Sets the <code>autoscrolls</code> property.
3116 * If <code>true</code> mouse dragged events will be
3117 * synthetically generated when the mouse is dragged
3118 * outside of the component's bounds and mouse motion
3119 * has paused (while the button continues to be held
3120 * down). The synthetic events make it appear that the
3121 * drag gesture has resumed in the direction established when
3122 * the component's boundary was crossed. Components that
3123 * support autoscrolling must handle <code>mouseDragged</code>
3124 * events by calling <code>scrollRectToVisible</code> with a
3125 * rectangle that contains the mouse event's location. All of
3126 * the Swing components that support item selection and are
3127 * typically displayed in a <code>JScrollPane</code>
3128 * (<code>JTable</code>, <code>JList</code>, <code>JTree</code>,
3129 * <code>JTextArea</code>, and <code>JEditorPane</code>)
3130 * already handle mouse dragged events in this way. To enable
3131 * autoscrolling in any other component, add a mouse motion
3132 * listener that calls <code>scrollRectToVisible</code>.
3133 * For example, given a <code>JPanel</code>, <code>myPanel</code>:
3134 * <pre>
3135 * MouseMotionListener doScrollRectToVisible = new MouseMotionAdapter() {
3136 * public void mouseDragged(MouseEvent e) {
3137 * Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);
3138 * ((JPanel)e.getSource()).scrollRectToVisible(r);
3139 * }
3140 * };
3141 * myPanel.addMouseMotionListener(doScrollRectToVisible);
3142 * </pre>
3143 * The default value of the <code>autoScrolls</code>
3144 * property is <code>false</code>.
3145 *
3146 * @param autoscrolls if true, synthetic mouse dragged events
3147 * are generated when the mouse is dragged outside of a component's
3148 * bounds and the mouse button continues to be held down; otherwise
3149 * false
3150 * @see #getAutoscrolls
3151 * @see JViewport
3152 * @see JScrollPane
3153 *
3154 * @beaninfo
3155 * expert: true
3156 * description: Determines if this component automatically scrolls its contents when dragged.
3157 */
3158 public void setAutoscrolls(boolean autoscrolls) {
3159 setFlag(AUTOSCROLLS_SET, true);
3160 if (this.autoscrolls != autoscrolls) {
3161 this.autoscrolls = autoscrolls;
3162 if (autoscrolls) {
3163 enableEvents(AWTEvent.MOUSE_EVENT_MASK);
3164 enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
3165 }
3166 else {
3167 Autoscroller.stop(this);
3168 }
3169 }
3170 }
3171
3172 /**
3173 * Gets the <code>autoscrolls</code> property.
3174 *
3175 * @return the value of the <code>autoscrolls</code> property
3176 * @see JViewport
3177 * @see #setAutoscrolls
3178 */
3179 public boolean getAutoscrolls() {
3180 return autoscrolls;
3181 }
3182
3183 /**
3184 * Sets the {@code TransferHandler}, which provides support for transfer
3185 * of data into and out of this component via cut/copy/paste and drag
3186 * and drop. This may be {@code null} if the component does not support
3187 * data transfer operations.
3188 * <p>
3189 * If the new {@code TransferHandler} is not {@code null}, this method
3190 * also installs a <b>new</b> {@code DropTarget} on the component to
3191 * activate drop handling through the {@code TransferHandler} and activate
3192 * any built-in support (such as calculating and displaying potential drop
3193 * locations). If you do not wish for this component to respond in any way
3194 * to drops, you can disable drop support entirely either by removing the
3195 * drop target ({@code setDropTarget(null)}) or by de-activating it
3196 * ({@code getDropTaget().setActive(false)}).
3197 * <p>
3198 * If the new {@code TransferHandler} is {@code null}, this method removes
3199 * the drop target.
3200 * <p>
3201 * Under two circumstances, this method does not modify the drop target:
3202 * First, if the existing drop target on this component was explicitly
3203 * set by the developer to a {@code non-null} value. Second, if the
3204 * system property {@code suppressSwingDropSupport} is {@code true}. The
3205 * default value for the system property is {@code false}.
3206 * <p>
3207 * Please see
3208 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/dnd.html">
3209 * How to Use Drag and Drop and Data Transfer</a>,
3210 * a section in <em>The Java Tutorial</em>, for more information.
3211 *
3212 * @param newHandler the new {@code TransferHandler}
3213 *
3214 * @see TransferHandler
3215 * @see #getTransferHandler
3216 * @since 1.4
3217 * @beaninfo
3218 * bound: true
3219 * hidden: true
3220 * description: Mechanism for transfer of data to and from the component
3221 */
3222 public void setTransferHandler(TransferHandler newHandler) {
3223 TransferHandler oldHandler = (TransferHandler)getClientProperty(
3224 JComponent_TRANSFER_HANDLER);
3225 putClientProperty(JComponent_TRANSFER_HANDLER, newHandler);
3226
3227 SwingUtilities.installSwingDropTargetAsNecessary(this, newHandler);
3228 firePropertyChange("transferHandler", oldHandler, newHandler);
3229 }
3230
3231 /**
3232 * Gets the <code>transferHandler</code> property.
3233 *
3234 * @return the value of the <code>transferHandler</code> property
3235 *
3236 * @see TransferHandler
3237 * @see #setTransferHandler
3238 * @since 1.4
3239 */
3240 public TransferHandler getTransferHandler() {
3241 return (TransferHandler)getClientProperty(JComponent_TRANSFER_HANDLER);
3242 }
3243
3244 /**
3245 * Calculates a custom drop location for this type of component,
3246 * representing where a drop at the given point should insert data.
3247 * <code>null</code> is returned if this component doesn't calculate
3248 * custom drop locations. In this case, <code>TransferHandler</code>
3249 * will provide a default <code>DropLocation</code> containing just
3250 * the point.
3251 *
3252 * @param p the point to calculate a drop location for
3253 * @return the drop location, or <code>null</code>
3254 */
3255 TransferHandler.DropLocation dropLocationForPoint(Point p) {
3256 return null;
3257 }
3258
3259 /**
3260 * Called to set or clear the drop location during a DnD operation.
3261 * In some cases, the component may need to use its internal selection
3262 * temporarily to indicate the drop location. To help facilitate this,
3263 * this method returns and accepts as a parameter a state object.
3264 * This state object can be used to store, and later restore, the selection
3265 * state. Whatever this method returns will be passed back to it in
3266 * future calls, as the state parameter. If it wants the DnD system to
3267 * continue storing the same state, it must pass it back every time.
3268 * Here's how this is used:
3269 * <p>
3270 * Let's say that on the first call to this method the component decides
3271 * to save some state (because it is about to use the selection to show
3272 * a drop index). It can return a state object to the caller encapsulating
3273 * any saved selection state. On a second call, let's say the drop location
3274 * is being changed to something else. The component doesn't need to
3275 * restore anything yet, so it simply passes back the same state object
3276 * to have the DnD system continue storing it. Finally, let's say this
3277 * method is messaged with <code>null</code>. This means DnD
3278 * is finished with this component for now, meaning it should restore
3279 * state. At this point, it can use the state parameter to restore
3280 * said state, and of course return <code>null</code> since there's
3281 * no longer anything to store.
3282 *
3283 * @param location the drop location (as calculated by
3284 * <code>dropLocationForPoint</code>) or <code>null</code>
3285 * if there's no longer a valid drop location
3286 * @param state the state object saved earlier for this component,
3287 * or <code>null</code>
3288 * @param forDrop whether or not the method is being called because an
3289 * actual drop occurred
3290 * @return any saved state for this component, or <code>null</code> if none
3291 */
3292 Object setDropLocation(TransferHandler.DropLocation location,
3293 Object state,
3294 boolean forDrop) {
3295
3296 return null;
3297 }
3298
3299 /**
3300 * Called to indicate to this component that DnD is done.
3301 * Needed by <code>JTree</code>.
3302 */
3303 void dndDone() {
3304 }
3305
3306 /**
3307 * Processes mouse events occurring on this component by
3308 * dispatching them to any registered
3309 * <code>MouseListener</code> objects, refer to
3310 * {@link java.awt.Component#processMouseEvent(MouseEvent)}
3311 * for a complete description of this method.
3312 *
3313 * @param e the mouse event
3314 * @see java.awt.Component#processMouseEvent
3315 * @since 1.5
3316 */
3317 protected void processMouseEvent(MouseEvent e) {
3318 if (autoscrolls && e.getID() == MouseEvent.MOUSE_RELEASED) {
3319 Autoscroller.stop(this);
3320 }
3321 super.processMouseEvent(e);
3322 }
3323
3324 /**
3325 * Processes mouse motion events, such as MouseEvent.MOUSE_DRAGGED.
3326 *
3327 * @param e the <code>MouseEvent</code>
3328 * @see MouseEvent
3329 */
3330 protected void processMouseMotionEvent(MouseEvent e) {
3331 boolean dispatch = true;
3332 if (autoscrolls && e.getID() == MouseEvent.MOUSE_DRAGGED) {
3333 // We don't want to do the drags when the mouse moves if we're
3334 // autoscrolling. It makes it feel spastic.
3335 dispatch = !Autoscroller.isRunning(this);
3336 Autoscroller.processMouseDragged(e);
3337 }
3338 if (dispatch) {
3339 super.processMouseMotionEvent(e);
3340 }
3341 }
3342
3343 // Inner classes can't get at this method from a super class
3344 void superProcessMouseMotionEvent(MouseEvent e) {
3345 super.processMouseMotionEvent(e);
3346 }
3347
3348 /**
3349 * This is invoked by the <code>RepaintManager</code> if
3350 * <code>createImage</code> is called on the component.
3351 *
3352 * @param newValue true if the double buffer image was created from this component
3353 */
3354 void setCreatedDoubleBuffer(boolean newValue) {
3355 setFlag(CREATED_DOUBLE_BUFFER, newValue);
3356 }
3357
3358 /**
3359 * Returns true if the <code>RepaintManager</code>
3360 * created the double buffer image from the component.
3361 *
3362 * @return true if this component had a double buffer image, false otherwise
3363 */
3364 boolean getCreatedDoubleBuffer() {
3365 return getFlag(CREATED_DOUBLE_BUFFER);
3366 }
3367
3368 /**
3369 * <code>ActionStandin</code> is used as a standin for
3370 * <code>ActionListeners</code> that are
3371 * added via <code>registerKeyboardAction</code>.
3372 */
3373 final class ActionStandin implements Action {
3374 private final ActionListener actionListener;
3375 private final String command;
3376 // This will be non-null if actionListener is an Action.
3377 private final Action action;
3378
3379 ActionStandin(ActionListener actionListener, String command) {
3380 this.actionListener = actionListener;
3381 if (actionListener instanceof Action) {
3382 this.action = (Action)actionListener;
3383 }
3384 else {
3385 this.action = null;
3386 }
3387 this.command = command;
3388 }
3389
3390 public Object getValue(String key) {
3391 if (key != null) {
3392 if (key.equals(Action.ACTION_COMMAND_KEY)) {
3393 return command;
3394 }
3395 if (action != null) {
3396 return action.getValue(key);
3397 }
3398 if (key.equals(NAME)) {
3399 return "ActionStandin";
3400 }
3401 }
3402 return null;
3403 }
3404
3405 public boolean isEnabled() {
3406 if (actionListener == null) {
3407 // This keeps the old semantics where
3408 // registerKeyboardAction(null) would essentialy remove
3409 // the binding. We don't remove the binding from the
3410 // InputMap as that would still allow parent InputMaps
3411 // bindings to be accessed.
3412 return false;
3413 }
3414 if (action == null) {
3415 return true;
3416 }
3417 return action.isEnabled();
3418 }
3419
3420 public void actionPerformed(ActionEvent ae) {
3421 if (actionListener != null) {
3422 actionListener.actionPerformed(ae);
3423 }
3424 }
3425
3426 // We don't allow any values to be added.
3427 public void putValue(String key, Object value) {}
3428
3429 // Does nothing, our enabledness is determiend from our asociated
3430 // action.
3431 public void setEnabled(boolean b) { }
3432
3433 public void addPropertyChangeListener
3434 (PropertyChangeListener listener) {}
3435 public void removePropertyChangeListener
3436 (PropertyChangeListener listener) {}
3437 }
3438
3439
3440 // This class is used by the KeyboardState class to provide a single
3441 // instance that can be stored in the AppContext.
3442 static final class IntVector {
3443 int array[] = null;
3444 int count = 0;
3445 int capacity = 0;
3446
3447 int size() {
3448 return count;
3449 }
3450
3451 int elementAt(int index) {
3452 return array[index];
3453 }
3454
3455 void addElement(int value) {
3456 if (count == capacity) {
3457 capacity = (capacity + 2) * 2;
3458 int[] newarray = new int[capacity];
3459 if (count > 0) {
3460 System.arraycopy(array, 0, newarray, 0, count);
3461 }
3462 array = newarray;
3463 }
3464 array[count++] = value;
3465 }
3466
3467 void setElementAt(int value, int index) {
3468 array[index] = value;
3469 }
3470 }
3471
3472 static class KeyboardState implements Serializable {
3473 private static final Object keyCodesKey =
3474 JComponent.KeyboardState.class;
3475
3476 // Get the array of key codes from the AppContext.
3477 static IntVector getKeyCodeArray() {
3478 IntVector iv =
3479 (IntVector)SwingUtilities.appContextGet(keyCodesKey);
3480 if (iv == null) {
3481 iv = new IntVector();
3482 SwingUtilities.appContextPut(keyCodesKey, iv);
3483 }
3484 return iv;
3485 }
3486
3487 static void registerKeyPressed(int keyCode) {
3488 IntVector kca = getKeyCodeArray();
3489 int count = kca.size();
3490 int i;
3491 for(i=0;i<count;i++) {
3492 if(kca.elementAt(i) == -1){
3493 kca.setElementAt(keyCode, i);
3494 return;
3495 }
3496 }
3497 kca.addElement(keyCode);
3498 }
3499
3500 static void registerKeyReleased(int keyCode) {
3501 IntVector kca = getKeyCodeArray();
3502 int count = kca.size();
3503 int i;
3504 for(i=0;i<count;i++) {
3505 if(kca.elementAt(i) == keyCode) {
3506 kca.setElementAt(-1, i);
3507 return;
3508 }
3509 }
3510 }
3511
3512 static boolean keyIsPressed(int keyCode) {
3513 IntVector kca = getKeyCodeArray();
3514 int count = kca.size();
3515 int i;
3516 for(i=0;i<count;i++) {
3517 if(kca.elementAt(i) == keyCode) {
3518 return true;
3519 }
3520 }
3521 return false;
3522 }
3523
3524 /**
3525 * Updates internal state of the KeyboardState and returns true
3526 * if the event should be processed further.
3527 */
3528 static boolean shouldProcess(KeyEvent e) {
3529 switch (e.getID()) {
3530 case KeyEvent.KEY_PRESSED:
3531 if (!keyIsPressed(e.getKeyCode())) {
3532 registerKeyPressed(e.getKeyCode());
3533 }
3534 return true;
3535 case KeyEvent.KEY_RELEASED:
3536 // We are forced to process VK_PRINTSCREEN separately because
3537 // the Windows doesn't generate the key pressed event for
3538 // printscreen and it block the processing of key release
3539 // event for printscreen.
3540 if (keyIsPressed(e.getKeyCode()) || e.getKeyCode()==KeyEvent.VK_PRINTSCREEN) {
3541 registerKeyReleased(e.getKeyCode());
3542 return true;
3543 }
3544 return false;
3545 case KeyEvent.KEY_TYPED:
3546 return true;
3547 default:
3548 // Not a known KeyEvent type, bail.
3549 return false;
3550 }
3551 }
3552 }
3553
3554 static final sun.awt.RequestFocusController focusController =
3555 new sun.awt.RequestFocusController() {
3556 public boolean acceptRequestFocus(Component from, Component to,
3557 boolean temporary, boolean focusedWindowChangeAllowed,
3558 sun.awt.CausedFocusEvent.Cause cause)
3559 {
3560 if ((to == null) || !(to instanceof JComponent)) {
3561 return true;
3562 }
3563
3564 if ((from == null) || !(from instanceof JComponent)) {
3565 return true;
3566 }
3567
3568 JComponent target = (JComponent) to;
3569 if (!target.getVerifyInputWhenFocusTarget()) {
3570 return true;
3571 }
3572
3573 JComponent jFocusOwner = (JComponent)from;
3574 InputVerifier iv = jFocusOwner.getInputVerifier();
3575
3576 if (iv == null) {
3577 return true;
3578 } else {
3579 Object currentSource = SwingUtilities.appContextGet(
3580 INPUT_VERIFIER_SOURCE_KEY);
3581 if (currentSource == jFocusOwner) {
3582 // We're currently calling into the InputVerifier
3583 // for this component, so allow the focus change.
3584 return true;
3585 }
3586 SwingUtilities.appContextPut(INPUT_VERIFIER_SOURCE_KEY,
3587 jFocusOwner);
3588 try {
3589 return iv.shouldYieldFocus(jFocusOwner);
3590 } finally {
3591 if (currentSource != null) {
3592 // We're already in the InputVerifier for
3593 // currentSource. By resetting the currentSource
3594 // we ensure that if the InputVerifier for
3595 // currentSource does a requestFocus, we don't
3596 // try and run the InputVerifier again.
3597 SwingUtilities.appContextPut(
3598 INPUT_VERIFIER_SOURCE_KEY, currentSource);
3599 } else {
3600 SwingUtilities.appContextRemove(
3601 INPUT_VERIFIER_SOURCE_KEY);
3602 }
3603 }
3604 }
3605 }
3606 };
3607
3608 /*
3609 * --- Accessibility Support ---
3610 */
3611
3612 /**
3613 * @deprecated As of JDK version 1.1,
3614 * replaced by <code>java.awt.Component.setEnabled(boolean)</code>.
3615 */
3616 @Deprecated
3617 public void enable() {
3618 if (isEnabled() != true) {
3619 super.enable();
3620 if (accessibleContext != null) {
3621 accessibleContext.firePropertyChange(
3622 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
3623 null, AccessibleState.ENABLED);
3624 }
3625 }
3626 }
3627
3628 /**
3629 * @deprecated As of JDK version 1.1,
3630 * replaced by <code>java.awt.Component.setEnabled(boolean)</code>.
3631 */
3632 @Deprecated
3633 public void disable() {
3634 if (isEnabled() != false) {
3635 super.disable();
3636 if (accessibleContext != null) {
3637 accessibleContext.firePropertyChange(
3638 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
3639 AccessibleState.ENABLED, null);
3640 }
3641 }
3642 }
3643
3644 /**
3645 * The <code>AccessibleContext</code> associated with this
3646 * <code>JComponent</code>.
3647 */
3648 protected AccessibleContext accessibleContext = null;
3649
3650 /**
3651 * Returns the <code>AccessibleContext</code> associated with this
3652 * <code>JComponent</code>. The method implemented by this base
3653 * class returns null. Classes that extend <code>JComponent</code>
3654 * should implement this method to return the
3655 * <code>AccessibleContext</code> associated with the subclass.
3656 *
3657 * @return the <code>AccessibleContext</code> of this
3658 * <code>JComponent</code>
3659 */
3660 public AccessibleContext getAccessibleContext() {
3661 return accessibleContext;
3662 }
3663
3664 /**
3665 * Inner class of JComponent used to provide default support for
3666 * accessibility. This class is not meant to be used directly by
3667 * application developers, but is instead meant only to be
3668 * subclassed by component developers.
3669 * <p>
3670 * <strong>Warning:</strong>
3671 * Serialized objects of this class will not be compatible with
3672 * future Swing releases. The current serialization support is
3673 * appropriate for short term storage or RMI between applications running
3674 * the same version of Swing. As of 1.4, support for long term storage
3675 * of all JavaBeans<sup><font size="-2">TM</font></sup>
3676 * has been added to the <code>java.beans</code> package.
3677 * Please see {@link java.beans.XMLEncoder}.
3678 */
3679 public abstract class AccessibleJComponent extends AccessibleAWTContainer
3680 implements AccessibleExtendedComponent
3681 {
3682 /**
3683 * Though the class is abstract, this should be called by
3684 * all sub-classes.
3685 */
3686 protected AccessibleJComponent() {
3687 super();
3688 }
3689
3690 protected ContainerListener accessibleContainerHandler = null;
3691 protected FocusListener accessibleFocusHandler = null;
3692
3693 /**
3694 * Fire PropertyChange listener, if one is registered,
3695 * when children added/removed.
3696 */
3697 protected class AccessibleContainerHandler
3698 implements ContainerListener {
3699 public void componentAdded(ContainerEvent e) {
3700 Component c = e.getChild();
3701 if (c != null && c instanceof Accessible) {
3702 AccessibleJComponent.this.firePropertyChange(
3703 AccessibleContext.ACCESSIBLE_CHILD_PROPERTY,
3704 null, c.getAccessibleContext());
3705 }
3706 }
3707 public void componentRemoved(ContainerEvent e) {
3708 Component c = e.getChild();
3709 if (c != null && c instanceof Accessible) {
3710 AccessibleJComponent.this.firePropertyChange(
3711 AccessibleContext.ACCESSIBLE_CHILD_PROPERTY,
3712 c.getAccessibleContext(), null);
3713 }
3714 }
3715 }
3716
3717 /**
3718 * Fire PropertyChange listener, if one is registered,
3719 * when focus events happen
3720 * @since 1.3
3721 */
3722 protected class AccessibleFocusHandler implements FocusListener {
3723 public void focusGained(FocusEvent event) {
3724 if (accessibleContext != null) {
3725 accessibleContext.firePropertyChange(
3726 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
3727 null, AccessibleState.FOCUSED);
3728 }
3729 }
3730 public void focusLost(FocusEvent event) {
3731 if (accessibleContext != null) {
3732 accessibleContext.firePropertyChange(
3733 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
3734 AccessibleState.FOCUSED, null);
3735 }
3736 }
3737 } // inner class AccessibleFocusHandler
3738
3739
3740 /**
3741 * Adds a PropertyChangeListener to the listener list.
3742 *
3743 * @param listener the PropertyChangeListener to be added
3744 */
3745 public void addPropertyChangeListener(PropertyChangeListener listener) {
3746 if (accessibleFocusHandler == null) {
3747 accessibleFocusHandler = new AccessibleFocusHandler();
3748 JComponent.this.addFocusListener(accessibleFocusHandler);
3749 }
3750 if (accessibleContainerHandler == null) {
3751 accessibleContainerHandler = new AccessibleContainerHandler();
3752 JComponent.this.addContainerListener(accessibleContainerHandler);
3753 }
3754 super.addPropertyChangeListener(listener);
3755 }
3756
3757 /**
3758 * Removes a PropertyChangeListener from the listener list.
3759 * This removes a PropertyChangeListener that was registered
3760 * for all properties.
3761 *
3762 * @param listener the PropertyChangeListener to be removed
3763 */
3764 public void removePropertyChangeListener(PropertyChangeListener listener) {
3765 if (accessibleFocusHandler != null) {
3766 JComponent.this.removeFocusListener(accessibleFocusHandler);
3767 accessibleFocusHandler = null;
3768 }
3769 super.removePropertyChangeListener(listener);
3770 }
3771
3772
3773
3774 /**
3775 * Recursively search through the border hierarchy (if it exists)
3776 * for a TitledBorder with a non-null title. This does a depth
3777 * first search on first the inside borders then the outside borders.
3778 * The assumption is that titles make really pretty inside borders
3779 * but not very pretty outside borders in compound border situations.
3780 * It's rather arbitrary, but hopefully decent UI programmers will
3781 * not create multiple titled borders for the same component.
3782 */
3783 protected String getBorderTitle(Border b) {
3784 String s;
3785 if (b instanceof TitledBorder) {
3786 return ((TitledBorder) b).getTitle();
3787 } else if (b instanceof CompoundBorder) {
3788 s = getBorderTitle(((CompoundBorder) b).getInsideBorder());
3789 if (s == null) {
3790 s = getBorderTitle(((CompoundBorder) b).getOutsideBorder());
3791 }
3792 return s;
3793 } else {
3794 return null;
3795 }
3796 }
3797
3798 // AccessibleContext methods
3799 //
3800 /**
3801 * Gets the accessible name of this object. This should almost never
3802 * return java.awt.Component.getName(), as that generally isn't
3803 * a localized name, and doesn't have meaning for the user. If the
3804 * object is fundamentally a text object (such as a menu item), the
3805 * accessible name should be the text of the object (for example,
3806 * "save").
3807 * If the object has a tooltip, the tooltip text may also be an
3808 * appropriate String to return.
3809 *
3810 * @return the localized name of the object -- can be null if this
3811 * object does not have a name
3812 * @see AccessibleContext#setAccessibleName
3813 */
3814 public String getAccessibleName() {
3815 String name = accessibleName;
3816
3817 // fallback to the client name property
3818 //
3819 if (name == null) {
3820 name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
3821 }
3822
3823 // fallback to the titled border if it exists
3824 //
3825 if (name == null) {
3826 name = getBorderTitle(getBorder());
3827 }
3828
3829 // fallback to the label labeling us if it exists
3830 //
3831 if (name == null) {
3832 Object o = getClientProperty(JLabel.LABELED_BY_PROPERTY);
3833 if (o instanceof Accessible) {
3834 AccessibleContext ac = ((Accessible) o).getAccessibleContext();
3835 if (ac != null) {
3836 name = ac.getAccessibleName();
3837 }
3838 }
3839 }
3840 return name;
3841 }
3842
3843 /**
3844 * Gets the accessible description of this object. This should be
3845 * a concise, localized description of what this object is - what
3846 * is its meaning to the user. If the object has a tooltip, the
3847 * tooltip text may be an appropriate string to return, assuming
3848 * it contains a concise description of the object (instead of just
3849 * the name of the object - for example a "Save" icon on a toolbar that
3850 * had "save" as the tooltip text shouldn't return the tooltip
3851 * text as the description, but something like "Saves the current
3852 * text document" instead).
3853 *
3854 * @return the localized description of the object -- can be null if
3855 * this object does not have a description
3856 * @see AccessibleContext#setAccessibleDescription
3857 */
3858 public String getAccessibleDescription() {
3859 String description = accessibleDescription;
3860
3861 // fallback to the client description property
3862 //
3863 if (description == null) {
3864 description = (String)getClientProperty(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY);
3865 }
3866
3867 // fallback to the tool tip text if it exists
3868 //
3869 if (description == null) {
3870 try {
3871 description = getToolTipText();
3872 } catch (Exception e) {
3873 // Just in case the subclass overrode the
3874 // getToolTipText method and actually
3875 // requires a MouseEvent.
3876 // [[[FIXME: WDW - we probably should require this
3877 // method to take a MouseEvent and just pass it on
3878 // to getToolTipText. The swing-feedback traffic
3879 // leads me to believe getToolTipText might change,
3880 // though, so I was hesitant to make this change at
3881 // this time.]]]
3882 }
3883 }
3884
3885 // fallback to the label labeling us if it exists
3886 //
3887 if (description == null) {
3888 Object o = getClientProperty(JLabel.LABELED_BY_PROPERTY);
3889 if (o instanceof Accessible) {
3890 AccessibleContext ac = ((Accessible) o).getAccessibleContext();
3891 if (ac != null) {
3892 description = ac.getAccessibleDescription();
3893 }
3894 }
3895 }
3896
3897 return description;
3898 }
3899
3900 /**
3901 * Gets the role of this object.
3902 *
3903 * @return an instance of AccessibleRole describing the role of the
3904 * object
3905 * @see AccessibleRole
3906 */
3907 public AccessibleRole getAccessibleRole() {
3908 return AccessibleRole.SWING_COMPONENT;
3909 }
3910
3911 /**
3912 * Gets the state of this object.
3913 *
3914 * @return an instance of AccessibleStateSet containing the current
3915 * state set of the object
3916 * @see AccessibleState
3917 */
3918 public AccessibleStateSet getAccessibleStateSet() {
3919 AccessibleStateSet states = super.getAccessibleStateSet();
3920 if (JComponent.this.isOpaque()) {
3921 states.add(AccessibleState.OPAQUE);
3922 }
3923 return states;
3924 }
3925
3926 /**
3927 * Returns the number of accessible children in the object. If all
3928 * of the children of this object implement Accessible, than this
3929 * method should return the number of children of this object.
3930 *
3931 * @return the number of accessible children in the object.
3932 */
3933 public int getAccessibleChildrenCount() {
3934 return super.getAccessibleChildrenCount();
3935 }
3936
3937 /**
3938 * Returns the nth Accessible child of the object.
3939 *
3940 * @param i zero-based index of child
3941 * @return the nth Accessible child of the object
3942 */
3943 public Accessible getAccessibleChild(int i) {
3944 return super.getAccessibleChild(i);
3945 }
3946
3947 // ----- AccessibleExtendedComponent
3948
3949 /**
3950 * Returns the AccessibleExtendedComponent
3951 *
3952 * @return the AccessibleExtendedComponent
3953 */
3954 AccessibleExtendedComponent getAccessibleExtendedComponent() {
3955 return this;
3956 }
3957
3958 /**
3959 * Returns the tool tip text
3960 *
3961 * @return the tool tip text, if supported, of the object;
3962 * otherwise, null
3963 * @since 1.4
3964 */
3965 public String getToolTipText() {
3966 return JComponent.this.getToolTipText();
3967 }
3968
3969 /**
3970 * Returns the titled border text
3971 *
3972 * @return the titled border text, if supported, of the object;
3973 * otherwise, null
3974 * @since 1.4
3975 */
3976 public String getTitledBorderText() {
3977 Border border = JComponent.this.getBorder();
3978 if (border instanceof TitledBorder) {
3979 return ((TitledBorder)border).getTitle();
3980 } else {
3981 return null;
3982 }
3983 }
3984
3985 /**
3986 * Returns key bindings associated with this object
3987 *
3988 * @return the key bindings, if supported, of the object;
3989 * otherwise, null
3990 * @see AccessibleKeyBinding
3991 * @since 1.4
3992 */
3993 public AccessibleKeyBinding getAccessibleKeyBinding() {
3994 return null;
3995 }
3996 } // inner class AccessibleJComponent
3997
3998
3999 /**
4000 * Returns an <code>ArrayTable</code> used for
4001 * key/value "client properties" for this component. If the
4002 * <code>clientProperties</code> table doesn't exist, an empty one
4003 * will be created.
4004 *
4005 * @return an ArrayTable
4006 * @see #putClientProperty
4007 * @see #getClientProperty
4008 */
4009 private ArrayTable getClientProperties() {
4010 if (clientProperties == null) {
4011 clientProperties = new ArrayTable();
4012 }
4013 return clientProperties;
4014 }
4015
4016
4017 /**
4018 * Returns the value of the property with the specified key. Only
4019 * properties added with <code>putClientProperty</code> will return
4020 * a non-<code>null</code> value.
4021 *
4022 * @param key the being queried
4023 * @return the value of this property or <code>null</code>
4024 * @see #putClientProperty
4025 */
4026 public final Object getClientProperty(Object key) {
4027 if (key == SwingUtilities2.AA_TEXT_PROPERTY_KEY) {
4028 return aaTextInfo;
4029 } else if (key == SwingUtilities2.COMPONENT_UI_PROPERTY_KEY) {
4030 return ui;
4031 }
4032 if(clientProperties == null) {
4033 return null;
4034 } else {
4035 synchronized(clientProperties) {
4036 return clientProperties.get(key);
4037 }
4038 }
4039 }
4040
4041 /**
4042 * Adds an arbitrary key/value "client property" to this component.
4043 * <p>
4044 * The <code>get/putClientProperty</code> methods provide access to
4045 * a small per-instance hashtable. Callers can use get/putClientProperty
4046 * to annotate components that were created by another module.
4047 * For example, a
4048 * layout manager might store per child constraints this way. For example:
4049 * <pre>
4050 * componentA.putClientProperty("to the left of", componentB);
4051 * </pre>
4052 * If value is <code>null</code> this method will remove the property.
4053 * Changes to client properties are reported with
4054 * <code>PropertyChange</code> events.
4055 * The name of the property (for the sake of PropertyChange
4056 * events) is <code>key.toString()</code>.
4057 * <p>
4058 * The <code>clientProperty</code> dictionary is not intended to
4059 * support large
4060 * scale extensions to JComponent nor should be it considered an
4061 * alternative to subclassing when designing a new component.
4062 *
4063 * @param key the new client property key
4064 * @param value the new client property value; if <code>null</code>
4065 * this method will remove the property
4066 * @see #getClientProperty
4067 * @see #addPropertyChangeListener
4068 */
4069 public final void putClientProperty(Object key, Object value) {
4070 if (key == SwingUtilities2.AA_TEXT_PROPERTY_KEY) {
4071 aaTextInfo = value;
4072 return;
4073 }
4074 if (value == null && clientProperties == null) {
4075 // Both the value and ArrayTable are null, implying we don't
4076 // have to do anything.
4077 return;
4078 }
4079 ArrayTable clientProperties = getClientProperties();
4080 Object oldValue;
4081 synchronized(clientProperties) {
4082 oldValue = clientProperties.get(key);
4083 if (value != null) {
4084 clientProperties.put(key, value);
4085 } else if (oldValue != null) {
4086 clientProperties.remove(key);
4087 } else {
4088 // old == new == null
4089 return;
4090 }
4091 }
4092 clientPropertyChanged(key, oldValue, value);
4093 firePropertyChange(key.toString(), oldValue, value);
4094 }
4095
4096 // Invoked from putClientProperty. This is provided for subclasses
4097 // in Swing.
4098 void clientPropertyChanged(Object key, Object oldValue,
4099 Object newValue) {
4100 }
4101
4102
4103 /*
4104 * Sets the property with the specified name to the specified value if
4105 * the property has not already been set by the client program.
4106 * This method is used primarily to set UI defaults for properties
4107 * with primitive types, where the values cannot be marked with
4108 * UIResource.
4109 * @see LookAndFeel#installProperty
4110 * @param propertyName String containing the name of the property
4111 * @param value Object containing the property value
4112 */
4113 void setUIProperty(String propertyName, Object value) {
4114 if (propertyName == "opaque") {
4115 if (!getFlag(OPAQUE_SET)) {
4116 setOpaque(((Boolean)value).booleanValue());
4117 setFlag(OPAQUE_SET, false);
4118 }
4119 } else if (propertyName == "autoscrolls") {
4120 if (!getFlag(AUTOSCROLLS_SET)) {
4121 setAutoscrolls(((Boolean)value).booleanValue());
4122 setFlag(AUTOSCROLLS_SET, false);
4123 }
4124 } else if (propertyName == "focusTraversalKeysForward") {
4125 if (!getFlag(FOCUS_TRAVERSAL_KEYS_FORWARD_SET)) {
4126 super.setFocusTraversalKeys(KeyboardFocusManager.
4127 FORWARD_TRAVERSAL_KEYS,
4128 (Set)value);
4129 }
4130 } else if (propertyName == "focusTraversalKeysBackward") {
4131 if (!getFlag(FOCUS_TRAVERSAL_KEYS_BACKWARD_SET)) {
4132 super.setFocusTraversalKeys(KeyboardFocusManager.
4133 BACKWARD_TRAVERSAL_KEYS,
4134 (Set)value);
4135 }
4136 } else {
4137 throw new IllegalArgumentException("property \""+
4138 propertyName+ "\" cannot be set using this method");
4139 }
4140 }
4141
4142
4143 /**
4144 * Sets the focus traversal keys for a given traversal operation for this
4145 * Component.
4146 * Refer to
4147 * {@link java.awt.Component#setFocusTraversalKeys}
4148 * for a complete description of this method.
4149 *
4150 * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
4151 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, or
4152 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS
4153 * @param keystrokes the Set of AWTKeyStroke for the specified operation
4154 * @see java.awt.KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
4155 * @see java.awt.KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
4156 * @see java.awt.KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
4157 * @throws IllegalArgumentException if id is not one of
4158 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
4159 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, or
4160 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or if keystrokes
4161 * contains null, or if any Object in keystrokes is not an
4162 * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event,
4163 * or if any keystroke already maps to another focus traversal
4164 * operation for this Component
4165 * @since 1.5
4166 * @beaninfo
4167 * bound: true
4168 */
4169 public void
4170 setFocusTraversalKeys(int id, Set<? extends AWTKeyStroke> keystrokes)
4171 {
4172 if (id == KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS) {
4173 setFlag(FOCUS_TRAVERSAL_KEYS_FORWARD_SET,true);
4174 } else if (id == KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS) {
4175 setFlag(FOCUS_TRAVERSAL_KEYS_BACKWARD_SET,true);
4176 }
4177 super.setFocusTraversalKeys(id,keystrokes);
4178 }
4179
4180 /* --- Transitional java.awt.Component Support ---
4181 * The methods and fields in this section will migrate to
4182 * java.awt.Component in the next JDK release.
4183 */
4184
4185 /**
4186 * Returns true if this component is lightweight, that is, if it doesn't
4187 * have a native window system peer.
4188 *
4189 * @return true if this component is lightweight
4190 */
4191 public static boolean isLightweightComponent(Component c) {
4192 return c.getPeer() instanceof LightweightPeer;
4193 }
4194
4195
4196 /**
4197 * @deprecated As of JDK 5,
4198 * replaced by <code>Component.setBounds(int, int, int, int)</code>.
4199 * <p>
4200 * Moves and resizes this component.
4201 *
4202 * @param x the new horizontal location
4203 * @param y the new vertical location
4204 * @param w the new width
4205 * @param h the new height
4206 * @see java.awt.Component#setBounds
4207 */
4208 @Deprecated
4209 public void reshape(int x, int y, int w, int h) {
4210 super.reshape(x, y, w, h);
4211 }
4212
4213
4214 /**
4215 * Stores the bounds of this component into "return value"
4216 * <code>rv</code> and returns <code>rv</code>.
4217 * If <code>rv</code> is <code>null</code> a new <code>Rectangle</code>
4218 * is allocated. This version of <code>getBounds</code> is useful
4219 * if the caller wants to avoid allocating a new <code>Rectangle</code>
4220 * object on the heap.
4221 *
4222 * @param rv the return value, modified to the component's bounds
4223 * @return <code>rv</code>; if <code>rv</code> is <code>null</code>
4224 * return a newly created <code>Rectangle</code> with this
4225 * component's bounds
4226 */
4227 public Rectangle getBounds(Rectangle rv) {
4228 if (rv == null) {
4229 return new Rectangle(getX(), getY(), getWidth(), getHeight());
4230 }
4231 else {
4232 rv.setBounds(getX(), getY(), getWidth(), getHeight());
4233 return rv;
4234 }
4235 }
4236
4237
4238 /**
4239 * Stores the width/height of this component into "return value"
4240 * <code>rv</code> and returns <code>rv</code>.
4241 * If <code>rv</code> is <code>null</code> a new <code>Dimension</code>
4242 * object is allocated. This version of <code>getSize</code>
4243 * is useful if the caller wants to avoid allocating a new
4244 * <code>Dimension</code> object on the heap.
4245 *
4246 * @param rv the return value, modified to the component's size
4247 * @return <code>rv</code>
4248 */
4249 public Dimension getSize(Dimension rv) {
4250 if (rv == null) {
4251 return new Dimension(getWidth(), getHeight());
4252 }
4253 else {
4254 rv.setSize(getWidth(), getHeight());
4255 return rv;
4256 }
4257 }
4258
4259
4260 /**
4261 * Stores the x,y origin of this component into "return value"
4262 * <code>rv</code> and returns <code>rv</code>.
4263 * If <code>rv</code> is <code>null</code> a new <code>Point</code>
4264 * is allocated. This version of <code>getLocation</code> is useful
4265 * if the caller wants to avoid allocating a new <code>Point</code>
4266 * object on the heap.
4267 *
4268 * @param rv the return value, modified to the component's location
4269 * @return <code>rv</code>
4270 */
4271 public Point getLocation(Point rv) {
4272 if (rv == null) {
4273 return new Point(getX(), getY());
4274 }
4275 else {
4276 rv.setLocation(getX(), getY());
4277 return rv;
4278 }
4279 }
4280
4281
4282 /**
4283 * Returns the current x coordinate of the component's origin.
4284 * This method is preferable to writing
4285 * <code>component.getBounds().x</code>, or
4286 * <code>component.getLocation().x</code> because it doesn't cause any
4287 * heap allocations.
4288 *
4289 * @return the current x coordinate of the component's origin
4290 */
4291 public int getX() { return super.getX(); }
4292
4293
4294 /**
4295 * Returns the current y coordinate of the component's origin.
4296 * This method is preferable to writing
4297 * <code>component.getBounds().y</code>, or
4298 * <code>component.getLocation().y</code> because it doesn't cause any
4299 * heap allocations.
4300 *
4301 * @return the current y coordinate of the component's origin
4302 */
4303 public int getY() { return super.getY(); }
4304
4305
4306 /**
4307 * Returns the current width of this component.
4308 * This method is preferable to writing
4309 * <code>component.getBounds().width</code>, or
4310 * <code>component.getSize().width</code> because it doesn't cause any
4311 * heap allocations.
4312 *
4313 * @return the current width of this component
4314 */
4315 public int getWidth() { return super.getWidth(); }
4316
4317
4318 /**
4319 * Returns the current height of this component.
4320 * This method is preferable to writing
4321 * <code>component.getBounds().height</code>, or
4322 * <code>component.getSize().height</code> because it doesn't cause any
4323 * heap allocations.
4324 *
4325 * @return the current height of this component
4326 */
4327 public int getHeight() { return super.getHeight(); }
4328
4329 /**
4330 * Returns true if this component is completely opaque.
4331 * <p>
4332 * An opaque component paints every pixel within its
4333 * rectangular bounds. A non-opaque component paints only a subset of
4334 * its pixels or none at all, allowing the pixels underneath it to
4335 * "show through". Therefore, a component that does not fully paint
4336 * its pixels provides a degree of transparency.
4337 * <p>
4338 * Subclasses that guarantee to always completely paint their contents
4339 * should override this method and return true.
4340 *
4341 * @return true if this component is completely opaque
4342 * @see #setOpaque
4343 */
4344 public boolean isOpaque() {
4345 return getFlag(IS_OPAQUE);
4346 }
4347
4348 /**
4349 * If true the component paints every pixel within its bounds.
4350 * Otherwise, the component may not paint some or all of its
4351 * pixels, allowing the underlying pixels to show through.
4352 * <p>
4353 * The default value of this property is false for <code>JComponent</code>.
4354 * However, the default value for this property on most standard
4355 * <code>JComponent</code> subclasses (such as <code>JButton</code> and
4356 * <code>JTree</code>) is look-and-feel dependent.
4357 *
4358 * @param isOpaque true if this component should be opaque
4359 * @see #isOpaque
4360 * @beaninfo
4361 * bound: true
4362 * expert: true
4363 * description: The component's opacity
4364 */
4365 public void setOpaque(boolean isOpaque) {
4366 boolean oldValue = getFlag(IS_OPAQUE);
4367 setFlag(IS_OPAQUE, isOpaque);
4368 setFlag(OPAQUE_SET, true);
4369 firePropertyChange("opaque", oldValue, isOpaque);
4370 }
4371
4372
4373 /**
4374 * If the specified rectangle is completely obscured by any of this
4375 * component's opaque children then returns true. Only direct children
4376 * are considered, more distant descendants are ignored. A
4377 * <code>JComponent</code> is opaque if
4378 * <code>JComponent.isOpaque()</code> returns true, other lightweight
4379 * components are always considered transparent, and heavyweight components
4380 * are always considered opaque.
4381 *
4382 * @param x x value of specified rectangle
4383 * @param y y value of specified rectangle
4384 * @param width width of specified rectangle
4385 * @param height height of specified rectangle
4386 * @return true if the specified rectangle is obscured by an opaque child
4387 */
4388 boolean rectangleIsObscured(int x,int y,int width,int height)
4389 {
4390 int numChildren = getComponentCount();
4391
4392 for(int i = 0; i < numChildren; i++) {
4393 Component child = getComponent(i);
4394 int cx, cy, cw, ch;
4395
4396 cx = child.getX();
4397 cy = child.getY();
4398 cw = child.getWidth();
4399 ch = child.getHeight();
4400
4401 if (x >= cx && (x + width) <= (cx + cw) &&
4402 y >= cy && (y + height) <= (cy + ch) && child.isVisible()) {
4403
4404 if(child instanceof JComponent) {
4405 // System.out.println("A) checking opaque: " + ((JComponent)child).isOpaque() + " " + child);
4406 // System.out.print("B) ");
4407 // Thread.dumpStack();
4408 return child.isOpaque();
4409 } else {
4410 /** Sometimes a heavy weight can have a bound larger than its peer size
4411 * so we should always draw under heavy weights
4412 */
4413 return false;
4414 }
4415 }
4416 }
4417
4418 return false;
4419 }
4420
4421
4422 /**
4423 * Returns the <code>Component</code>'s "visible rect rectangle" - the
4424 * intersection of the visible rectangles for the component <code>c</code>
4425 * and all of its ancestors. The return value is stored in
4426 * <code>visibleRect</code>.
4427 *
4428 * @param c the component
4429 * @param visibleRect a <code>Rectangle</code> computed as the
4430 * intersection of all visible rectangles for the component
4431 * <code>c</code> and all of its ancestors -- this is the
4432 * return value for this method
4433 * @see #getVisibleRect
4434 */
4435 static final void computeVisibleRect(Component c, Rectangle visibleRect) {
4436 Container p = c.getParent();
4437 Rectangle bounds = c.getBounds();
4438
4439 if (p == null || p instanceof Window || p instanceof Applet) {
4440 visibleRect.setBounds(0, 0, bounds.width, bounds.height);
4441 } else {
4442 computeVisibleRect(p, visibleRect);
4443 visibleRect.x -= bounds.x;
4444 visibleRect.y -= bounds.y;
4445 SwingUtilities.computeIntersection(0,0,bounds.width,bounds.height,visibleRect);
4446 }
4447 }
4448
4449
4450 /**
4451 * Returns the <code>Component</code>'s "visible rect rectangle" - the
4452 * intersection of the visible rectangles for this component
4453 * and all of its ancestors. The return value is stored in
4454 * <code>visibleRect</code>.
4455 *
4456 * @param visibleRect a <code>Rectangle</code> computed as the
4457 * intersection of all visible rectangles for this
4458 * component and all of its ancestors -- this is the return
4459 * value for this method
4460 * @see #getVisibleRect
4461 */
4462 public void computeVisibleRect(Rectangle visibleRect) {
4463 computeVisibleRect(this, visibleRect);
4464 }
4465
4466
4467 /**
4468 * Returns the <code>Component</code>'s "visible rectangle" - the
4469 * intersection of this component's visible rectangle,
4470 * <code>new Rectangle(0, 0, getWidth(), getHeight())</code>,
4471 * and all of its ancestors' visible rectangles.
4472 *
4473 * @return the visible rectangle
4474 */
4475 public Rectangle getVisibleRect() {
4476 Rectangle visibleRect = new Rectangle();
4477
4478 computeVisibleRect(visibleRect);
4479 return visibleRect;
4480 }
4481
4482 /**
4483 * Support for reporting bound property changes for boolean properties.
4484 * This method can be called when a bound property has changed and it will
4485 * send the appropriate PropertyChangeEvent to any registered
4486 * PropertyChangeListeners.
4487 *
4488 * @param propertyName the property whose value has changed
4489 * @param oldValue the property's previous value
4490 * @param newValue the property's new value
4491 */
4492 public void firePropertyChange(String propertyName,
4493 boolean oldValue, boolean newValue) {
4494 super.firePropertyChange(propertyName, oldValue, newValue);
4495 }
4496
4497
4498 /**
4499 * Support for reporting bound property changes for integer properties.
4500 * This method can be called when a bound property has changed and it will
4501 * send the appropriate PropertyChangeEvent to any registered
4502 * PropertyChangeListeners.
4503 *
4504 * @param propertyName the property whose value has changed
4505 * @param oldValue the property's previous value
4506 * @param newValue the property's new value
4507 */
4508 public void firePropertyChange(String propertyName,
4509 int oldValue, int newValue) {
4510 super.firePropertyChange(propertyName, oldValue, newValue);
4511 }
4512
4513 // XXX This method is implemented as a workaround to a JLS issue with ambiguous
4514 // methods. This should be removed once 4758654 is resolved.
4515 public void firePropertyChange(String propertyName, char oldValue, char newValue) {
4516 super.firePropertyChange(propertyName, oldValue, newValue);
4517 }
4518
4519 /**
4520 * Supports reporting constrained property changes.
4521 * This method can be called when a constrained property has changed
4522 * and it will send the appropriate <code>PropertyChangeEvent</code>
4523 * to any registered <code>VetoableChangeListeners</code>.
4524 *
4525 * @param propertyName the name of the property that was listened on
4526 * @param oldValue the old value of the property
4527 * @param newValue the new value of the property
4528 * @exception PropertyVetoException when the attempt to set the
4529 * property is vetoed by the component
4530 */
4531 protected void fireVetoableChange(String propertyName, Object oldValue, Object newValue)
4532 throws java.beans.PropertyVetoException
4533 {
4534 if (vetoableChangeSupport == null) {
4535 return;
4536 }
4537 vetoableChangeSupport.fireVetoableChange(propertyName, oldValue, newValue);
4538 }
4539
4540
4541 /**
4542 * Adds a <code>VetoableChangeListener</code> to the listener list.
4543 * The listener is registered for all properties.
4544 *
4545 * @param listener the <code>VetoableChangeListener</code> to be added
4546 */
4547 public synchronized void addVetoableChangeListener(VetoableChangeListener listener) {
4548 if (vetoableChangeSupport == null) {
4549 vetoableChangeSupport = new java.beans.VetoableChangeSupport(this);
4550 }
4551 vetoableChangeSupport.addVetoableChangeListener(listener);
4552 }
4553
4554
4555 /**
4556 * Removes a <code>VetoableChangeListener</code> from the listener list.
4557 * This removes a <code>VetoableChangeListener</code> that was registered
4558 * for all properties.
4559 *
4560 * @param listener the <code>VetoableChangeListener</code> to be removed
4561 */
4562 public synchronized void removeVetoableChangeListener(VetoableChangeListener listener) {
4563 if (vetoableChangeSupport == null) {
4564 return;
4565 }
4566 vetoableChangeSupport.removeVetoableChangeListener(listener);
4567 }
4568
4569
4570 /**
4571 * Returns an array of all the vetoable change listeners
4572 * registered on this component.
4573 *
4574 * @return all of the component's <code>VetoableChangeListener</code>s
4575 * or an empty
4576 * array if no vetoable change listeners are currently registered
4577 *
4578 * @see #addVetoableChangeListener
4579 * @see #removeVetoableChangeListener
4580 *
4581 * @since 1.4
4582 */
4583 public synchronized VetoableChangeListener[] getVetoableChangeListeners() {
4584 if (vetoableChangeSupport == null) {
4585 return new VetoableChangeListener[0];
4586 }
4587 return vetoableChangeSupport.getVetoableChangeListeners();
4588 }
4589
4590
4591 /**
4592 * Returns the top-level ancestor of this component (either the
4593 * containing <code>Window</code> or <code>Applet</code>),
4594 * or <code>null</code> if this component has not
4595 * been added to any container.
4596 *
4597 * @return the top-level <code>Container</code> that this component is in,
4598 * or <code>null</code> if not in any container
4599 */
4600 public Container getTopLevelAncestor() {
4601 for(Container p = this; p != null; p = p.getParent()) {
4602 if(p instanceof Window || p instanceof Applet) {
4603 return p;
4604 }
4605 }
4606 return null;
4607 }
4608
4609 private AncestorNotifier getAncestorNotifier() {
4610 return (AncestorNotifier)
4611 getClientProperty(JComponent_ANCESTOR_NOTIFIER);
4612 }
4613
4614 /**
4615 * Registers <code>listener</code> so that it will receive
4616 * <code>AncestorEvents</code> when it or any of its ancestors
4617 * move or are made visible or invisible.
4618 * Events are also sent when the component or its ancestors are added
4619 * or removed from the containment hierarchy.
4620 *
4621 * @param listener the <code>AncestorListener</code> to register
4622 * @see AncestorEvent
4623 */
4624 public void addAncestorListener(AncestorListener listener) {
4625 AncestorNotifier ancestorNotifier = getAncestorNotifier();
4626 if (ancestorNotifier == null) {
4627 ancestorNotifier = new AncestorNotifier(this);
4628 putClientProperty(JComponent_ANCESTOR_NOTIFIER,
4629 ancestorNotifier);
4630 }
4631 ancestorNotifier.addAncestorListener(listener);
4632 }
4633
4634 /**
4635 * Unregisters <code>listener</code> so that it will no longer receive
4636 * <code>AncestorEvents</code>.
4637 *
4638 * @param listener the <code>AncestorListener</code> to be removed
4639 * @see #addAncestorListener
4640 */
4641 public void removeAncestorListener(AncestorListener listener) {
4642 AncestorNotifier ancestorNotifier = getAncestorNotifier();
4643 if (ancestorNotifier == null) {
4644 return;
4645 }
4646 ancestorNotifier.removeAncestorListener(listener);
4647 if (ancestorNotifier.listenerList.getListenerList().length == 0) {
4648 ancestorNotifier.removeAllListeners();
4649 putClientProperty(JComponent_ANCESTOR_NOTIFIER, null);
4650 }
4651 }
4652
4653 /**
4654 * Returns an array of all the ancestor listeners
4655 * registered on this component.
4656 *
4657 * @return all of the component's <code>AncestorListener</code>s
4658 * or an empty
4659 * array if no ancestor listeners are currently registered
4660 *
4661 * @see #addAncestorListener
4662 * @see #removeAncestorListener
4663 *
4664 * @since 1.4
4665 */
4666 public AncestorListener[] getAncestorListeners() {
4667 AncestorNotifier ancestorNotifier = getAncestorNotifier();
4668 if (ancestorNotifier == null) {
4669 return new AncestorListener[0];
4670 }
4671 return ancestorNotifier.getAncestorListeners();
4672 }
4673
4674 /**
4675 * Returns an array of all the objects currently registered
4676 * as <code><em>Foo</em>Listener</code>s
4677 * upon this <code>JComponent</code>.
4678 * <code><em>Foo</em>Listener</code>s are registered using the
4679 * <code>add<em>Foo</em>Listener</code> method.
4680 *
4681 * <p>
4682 *
4683 * You can specify the <code>listenerType</code> argument
4684 * with a class literal,
4685 * such as
4686 * <code><em>Foo</em>Listener.class</code>.
4687 * For example, you can query a
4688 * <code>JComponent</code> <code>c</code>
4689 * for its mouse listeners with the following code:
4690 * <pre>MouseListener[] mls = (MouseListener[])(c.getListeners(MouseListener.class));</pre>
4691 * If no such listeners exist, this method returns an empty array.
4692 *
4693 * @param listenerType the type of listeners requested; this parameter
4694 * should specify an interface that descends from
4695 * <code>java.util.EventListener</code>
4696 * @return an array of all objects registered as
4697 * <code><em>Foo</em>Listener</code>s on this component,
4698 * or an empty array if no such
4699 * listeners have been added
4700 * @exception ClassCastException if <code>listenerType</code>
4701 * doesn't specify a class or interface that implements
4702 * <code>java.util.EventListener</code>
4703 *
4704 * @since 1.3
4705 *
4706 * @see #getVetoableChangeListeners
4707 * @see #getAncestorListeners
4708 */
4709 public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
4710 T[] result;
4711 if (listenerType == AncestorListener.class) {
4712 // AncestorListeners are handled by the AncestorNotifier
4713 result = (T[])getAncestorListeners();
4714 }
4715 else if (listenerType == VetoableChangeListener.class) {
4716 // VetoableChangeListeners are handled by VetoableChangeSupport
4717 result = (T[])getVetoableChangeListeners();
4718 }
4719 else if (listenerType == PropertyChangeListener.class) {
4720 // PropertyChangeListeners are handled by PropertyChangeSupport
4721 result = (T[])getPropertyChangeListeners();
4722 }
4723 else {
4724 result = listenerList.getListeners(listenerType);
4725 }
4726
4727 if (result.length == 0) {
4728 return super.getListeners(listenerType);
4729 }
4730 return result;
4731 }
4732
4733 /**
4734 * Notifies this component that it now has a parent component.
4735 * When this method is invoked, the chain of parent components is
4736 * set up with <code>KeyboardAction</code> event listeners.
4737 * This method is called by the toolkit internally and should
4738 * not be called directly by programs.
4739 *
4740 * @see #registerKeyboardAction
4741 */
4742 public void addNotify() {
4743 super.addNotify();
4744 firePropertyChange("ancestor", null, getParent());
4745
4746 registerWithKeyboardManager(false);
4747 registerNextFocusableComponent();
4748 }
4749
4750
4751 /**
4752 * Notifies this component that it no longer has a parent component.
4753 * When this method is invoked, any <code>KeyboardAction</code>s
4754 * set up in the the chain of parent components are removed.
4755 * This method is called by the toolkit internally and should
4756 * not be called directly by programs.
4757 *
4758 * @see #registerKeyboardAction
4759 */
4760 public void removeNotify() {
4761 super.removeNotify();
4762 // This isn't strictly correct. The event shouldn't be
4763 // fired until *after* the parent is set to null. But
4764 // we only get notified before that happens
4765 firePropertyChange("ancestor", getParent(), null);
4766
4767 unregisterWithKeyboardManager();
4768 deregisterNextFocusableComponent();
4769
4770 if (getCreatedDoubleBuffer()) {
4771 RepaintManager.currentManager(this).resetDoubleBuffer();
4772 setCreatedDoubleBuffer(false);
4773 }
4774 if (autoscrolls) {
4775 Autoscroller.stop(this);
4776 }
4777 }
4778
4779
4780 /**
4781 * Adds the specified region to the dirty region list if the component
4782 * is showing. The component will be repainted after all of the
4783 * currently pending events have been dispatched.
4784 *
4785 * @param tm this parameter is not used
4786 * @param x the x value of the dirty region
4787 * @param y the y value of the dirty region
4788 * @param width the width of the dirty region
4789 * @param height the height of the dirty region
4790 * @see #isPaintingOrigin()
4791 * @see java.awt.Component#isShowing
4792 * @see RepaintManager#addDirtyRegion
4793 */
4794 public void repaint(long tm, int x, int y, int width, int height) {
4795 RepaintManager.currentManager(this).addDirtyRegion(this, x, y, width, height);
4796 }
4797
4798
4799 /**
4800 * Adds the specified region to the dirty region list if the component
4801 * is showing. The component will be repainted after all of the
4802 * currently pending events have been dispatched.
4803 *
4804 * @param r a <code>Rectangle</code> containing the dirty region
4805 * @see #isPaintingOrigin()
4806 * @see java.awt.Component#isShowing
4807 * @see RepaintManager#addDirtyRegion
4808 */
4809 public void repaint(Rectangle r) {
4810 repaint(0,r.x,r.y,r.width,r.height);
4811 }
4812
4813
4814 /**
4815 * Supports deferred automatic layout.
4816 * <p>
4817 * Calls <code>invalidate</code> and then adds this component's
4818 * <code>validateRoot</code> to a list of components that need to be
4819 * validated. Validation will occur after all currently pending
4820 * events have been dispatched. In other words after this method
4821 * is called, the first validateRoot (if any) found when walking
4822 * up the containment hierarchy of this component will be validated.
4823 * By default, <code>JRootPane</code>, <code>JScrollPane</code>,
4824 * and <code>JTextField</code> return true
4825 * from <code>isValidateRoot</code>.
4826 * <p>
4827 * This method will automatically be called on this component
4828 * when a property value changes such that size, location, or
4829 * internal layout of this component has been affected. This automatic
4830 * updating differs from the AWT because programs generally no
4831 * longer need to invoke <code>validate</code> to get the contents of the
4832 * GUI to update.
4833 * <p>
4834 *
4835 * @see java.awt.Component#invalidate
4836 * @see java.awt.Container#validate
4837 * @see #isValidateRoot
4838 * @see RepaintManager#addInvalidComponent
4839 */
4840 public void revalidate() {
4841 if (getParent() == null) {
4842 // Note: We don't bother invalidating here as once added
4843 // to a valid parent invalidate will be invoked (addImpl
4844 // invokes addNotify which will invoke invalidate on the
4845 // new Component). Also, if we do add a check to isValid
4846 // here it can potentially be called before the constructor
4847 // which was causing some people grief.
4848 return;
4849 }
4850 if (SwingUtilities.isEventDispatchThread()) {
4851 invalidate();
4852 RepaintManager.currentManager(this).addInvalidComponent(this);
4853 }
4854 else {
4855 // To avoid a flood of Runnables when constructing GUIs off
4856 // the EDT, a flag is maintained as to whether or not
4857 // a Runnable has been scheduled.
4858 synchronized(this) {
4859 if (getFlag(REVALIDATE_RUNNABLE_SCHEDULED)) {
4860 return;
4861 }
4862 setFlag(REVALIDATE_RUNNABLE_SCHEDULED, true);
4863 }
4864 Runnable callRevalidate = new Runnable() {
4865 public void run() {
4866 synchronized(JComponent.this) {
4867 setFlag(REVALIDATE_RUNNABLE_SCHEDULED, false);
4868 }
4869 revalidate();
4870 }
4871 };
4872 SwingUtilities.invokeLater(callRevalidate);
4873 }
4874 }
4875
4876 /**
4877 * If this method returns true, <code>revalidate</code> calls by
4878 * descendants of this component will cause the entire tree
4879 * beginning with this root to be validated.
4880 * Returns false by default. <code>JScrollPane</code> overrides
4881 * this method and returns true.
4882 *
4883 * @return always returns false
4884 * @see #revalidate
4885 * @see java.awt.Component#invalidate
4886 * @see java.awt.Container#validate
4887 * @see java.awt.Container#isValidateRoot
4888 */
4889 @Override
4890 public boolean isValidateRoot() {
4891 return false;
4892 }
4893
4894
4895 /**
4896 * Returns true if this component tiles its children -- that is, if
4897 * it can guarantee that the children will not overlap. The
4898 * repainting system is substantially more efficient in this
4899 * common case. <code>JComponent</code> subclasses that can't make this
4900 * guarantee, such as <code>JLayeredPane</code>,
4901 * should override this method to return false.
4902 *
4903 * @return always returns true
4904 */
4905 public boolean isOptimizedDrawingEnabled() {
4906 return true;
4907 }
4908
4909 /**
4910 * Returns {@code true} if a paint triggered on a child component should cause
4911 * painting to originate from this Component, or one of its ancestors.
4912 * <p/>
4913 * Calling {@link #repaint} or {@link #paintImmediately(int, int, int, int)}
4914 * on a Swing component will result in calling
4915 * the {@link JComponent#paintImmediately(int, int, int, int)} method of
4916 * the first ancestor which {@code isPaintingOrigin()} returns {@code true}, if there are any.
4917 * <p/>
4918 * {@code JComponent} subclasses that need to be painted when any of their
4919 * children are repainted should override this method to return {@code true}.
4920 *
4921 * @return always returns {@code false}
4922 *
4923 * @see #paintImmediately(int, int, int, int)
4924 */
4925 protected boolean isPaintingOrigin() {
4926 return false;
4927 }
4928
4929 /**
4930 * Paints the specified region in this component and all of its
4931 * descendants that overlap the region, immediately.
4932 * <p>
4933 * It's rarely necessary to call this method. In most cases it's
4934 * more efficient to call repaint, which defers the actual painting
4935 * and can collapse redundant requests into a single paint call.
4936 * This method is useful if one needs to update the display while
4937 * the current event is being dispatched.
4938 * <p>
4939 * This method is to be overridden when the dirty region needs to be changed
4940 * for components that are painting origins.
4941 *
4942 * @param x the x value of the region to be painted
4943 * @param y the y value of the region to be painted
4944 * @param w the width of the region to be painted
4945 * @param h the height of the region to be painted
4946 * @see #repaint
4947 * @see #isPaintingOrigin()
4948 */
4949 public void paintImmediately(int x,int y,int w, int h) {
4950 Component c = this;
4951 Component parent;
4952
4953 if(!isShowing()) {
4954 return;
4955 }
4956
4957 JComponent paintingOigin = SwingUtilities.getPaintingOrigin(this);
4958 if (paintingOigin != null) {
4959 Rectangle rectangle = SwingUtilities.convertRectangle(
4960 c, new Rectangle(x, y, w, h), paintingOigin);
4961 paintingOigin.paintImmediately(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
4962 return;
4963 }
4964
4965 while(!c.isOpaque()) {
4966 parent = c.getParent();
4967 if(parent != null) {
4968 x += c.getX();
4969 y += c.getY();
4970 c = parent;
4971 } else {
4972 break;
4973 }
4974
4975 if(!(c instanceof JComponent)) {
4976 break;
4977 }
4978 }
4979 if(c instanceof JComponent) {
4980 ((JComponent)c)._paintImmediately(x,y,w,h);
4981 } else {
4982 c.repaint(x,y,w,h);
4983 }
4984 }
4985
4986 /**
4987 * Paints the specified region now.
4988 *
4989 * @param r a <code>Rectangle</code> containing the region to be painted
4990 */
4991 public void paintImmediately(Rectangle r) {
4992 paintImmediately(r.x,r.y,r.width,r.height);
4993 }
4994
4995 /**
4996 * Returns whether this component should be guaranteed to be on top.
4997 * For example, it would make no sense for <code>Menu</code>s to pop up
4998 * under another component, so they would always return true.
4999 * Most components will want to return false, hence that is the default.
5000 *
5001 * @return always returns false
5002 */
5003 // package private
5004 boolean alwaysOnTop() {
5005 return false;
5006 }
5007
5008 void setPaintingChild(Component paintingChild) {
5009 this.paintingChild = paintingChild;
5010 }
5011
5012 void _paintImmediately(int x, int y, int w, int h) {
5013 Graphics g;
5014 Container c;
5015 Rectangle b;
5016
5017 int tmpX, tmpY, tmpWidth, tmpHeight;
5018 int offsetX=0,offsetY=0;
5019
5020 boolean hasBuffer = false;
5021
5022 JComponent bufferedComponent = null;
5023 JComponent paintingComponent = this;
5024
5025 RepaintManager repaintManager = RepaintManager.currentManager(this);
5026 // parent Container's up to Window or Applet. First container is
5027 // the direct parent. Note that in testing it was faster to
5028 // alloc a new Vector vs keeping a stack of them around, and gc
5029 // seemed to have a minimal effect on this.
5030 java.util.List<Component> path = new java.util.ArrayList<Component>(7);
5031 int pIndex = -1;
5032 int pCount = 0;
5033
5034 tmpX = tmpY = tmpWidth = tmpHeight = 0;
5035
5036 Rectangle paintImmediatelyClip = fetchRectangle();
5037 paintImmediatelyClip.x = x;
5038 paintImmediatelyClip.y = y;
5039 paintImmediatelyClip.width = w;
5040 paintImmediatelyClip.height = h;
5041
5042
5043 // System.out.println("1) ************* in _paintImmediately for " + this);
5044
5045 boolean ontop = alwaysOnTop() && isOpaque();
5046 if (ontop) {
5047 SwingUtilities.computeIntersection(0, 0, getWidth(), getHeight(),
5048 paintImmediatelyClip);
5049 if (paintImmediatelyClip.width == 0) {
5050 recycleRectangle(paintImmediatelyClip);
5051 return;
5052 }
5053 }
5054 Component child;
5055 for (c = this, child = null;
5056 c != null && !(c instanceof Window) && !(c instanceof Applet);
5057 child = c, c = c.getParent()) {
5058 JComponent jc = (c instanceof JComponent) ? (JComponent)c :
5059 null;
5060 path.add(c);
5061 if(!ontop && jc != null && !jc.isOptimizedDrawingEnabled()) {
5062 boolean resetPC;
5063
5064 // Children of c may overlap, three possible cases for the
5065 // painting region:
5066 // . Completely obscured by an opaque sibling, in which
5067 // case there is no need to paint.
5068 // . Partially obscured by a sibling: need to start
5069 // painting from c.
5070 // . Otherwise we aren't obscured and thus don't need to
5071 // start painting from parent.
5072 if (c != this) {
5073 if (jc.isPaintingOrigin()) {
5074 resetPC = true;
5075 }
5076 else {
5077 Component[] children = c.getComponents();
5078 int i = 0;
5079 for (; i<children.length; i++) {
5080 if (children[i] == child) break;
5081 }
5082 switch (jc.getObscuredState(i,
5083 paintImmediatelyClip.x,
5084 paintImmediatelyClip.y,
5085 paintImmediatelyClip.width,
5086 paintImmediatelyClip.height)) {
5087 case NOT_OBSCURED:
5088 resetPC = false;
5089 break;
5090 case COMPLETELY_OBSCURED:
5091 recycleRectangle(paintImmediatelyClip);
5092 return;
5093 default:
5094 resetPC = true;
5095 break;
5096 }
5097 }
5098 }
5099 else {
5100 resetPC = false;
5101 }
5102
5103 if (resetPC) {
5104 // Get rid of any buffer since we draw from here and
5105 // we might draw something larger
5106 paintingComponent = jc;
5107 pIndex = pCount;
5108 offsetX = offsetY = 0;
5109 hasBuffer = false;
5110 }
5111 }
5112 pCount++;
5113
5114 // look to see if the parent (and therefor this component)
5115 // is double buffered
5116 if(repaintManager.isDoubleBufferingEnabled() && jc != null &&
5117 jc.isDoubleBuffered()) {
5118 hasBuffer = true;
5119 bufferedComponent = jc;
5120 }
5121
5122 // if we aren't on top, include the parent's clip
5123 if (!ontop) {
5124 int bx = c.getX();
5125 int by = c.getY();
5126 tmpWidth = c.getWidth();
5127 tmpHeight = c.getHeight();
5128 SwingUtilities.computeIntersection(tmpX,tmpY,tmpWidth,tmpHeight,paintImmediatelyClip);
5129 paintImmediatelyClip.x += bx;
5130 paintImmediatelyClip.y += by;
5131 offsetX += bx;
5132 offsetY += by;
5133 }
5134 }
5135
5136 // If the clip width or height is negative, don't bother painting
5137 if(c == null || c.getPeer() == null ||
5138 paintImmediatelyClip.width <= 0 ||
5139 paintImmediatelyClip.height <= 0) {
5140 recycleRectangle(paintImmediatelyClip);
5141 return;
5142 }
5143
5144 paintingComponent.setFlag(IS_REPAINTING, true);
5145
5146 paintImmediatelyClip.x -= offsetX;
5147 paintImmediatelyClip.y -= offsetY;
5148
5149 // Notify the Components that are going to be painted of the
5150 // child component to paint to.
5151 if(paintingComponent != this) {
5152 Component comp;
5153 int i = pIndex;
5154 for(; i > 0 ; i--) {
5155 comp = path.get(i);
5156 if(comp instanceof JComponent) {
5157 ((JComponent)comp).setPaintingChild(path.get(i-1));
5158 }
5159 }
5160 }
5161 try {
5162 if ((g = safelyGetGraphics(paintingComponent, c)) != null) {
5163 try {
5164 if (hasBuffer) {
5165 RepaintManager rm = RepaintManager.currentManager(
5166 bufferedComponent);
5167 rm.beginPaint();
5168 try {
5169 rm.paint(paintingComponent, bufferedComponent, g,
5170 paintImmediatelyClip.x,
5171 paintImmediatelyClip.y,
5172 paintImmediatelyClip.width,
5173 paintImmediatelyClip.height);
5174 } finally {
5175 rm.endPaint();
5176 }
5177 } else {
5178 g.setClip(paintImmediatelyClip.x, paintImmediatelyClip.y,
5179 paintImmediatelyClip.width, paintImmediatelyClip.height);
5180 paintingComponent.paint(g);
5181 }
5182 } finally {
5183 g.dispose();
5184 }
5185 }
5186 }
5187 finally {
5188 // Reset the painting child for the parent components.
5189 if(paintingComponent != this) {
5190 Component comp;
5191 int i = pIndex;
5192 for(; i > 0 ; i--) {
5193 comp = path.get(i);
5194 if(comp instanceof JComponent) {
5195 ((JComponent)comp).setPaintingChild(null);
5196 }
5197 }
5198 }
5199 paintingComponent.setFlag(IS_REPAINTING, false);
5200 }
5201 recycleRectangle(paintImmediatelyClip);
5202 }
5203
5204 /**
5205 * Paints to the specified graphics. This does not set the clip and it
5206 * does not adjust the Graphics in anyway, callers must do that first.
5207 * This method is package-private for RepaintManager.PaintManager and
5208 * its subclasses to call, it is NOT intended for general use outside
5209 * of that.
5210 */
5211 void paintToOffscreen(Graphics g, int x, int y, int w, int h, int maxX,
5212 int maxY) {
5213 try {
5214 setFlag(ANCESTOR_USING_BUFFER, true);
5215 if ((y + h) < maxY || (x + w) < maxX) {
5216 setFlag(IS_PAINTING_TILE, true);
5217 }
5218 if (getFlag(IS_REPAINTING)) {
5219 // Called from paintImmediately (RepaintManager) to fill
5220 // repaint request
5221 paint(g);
5222 } else {
5223 // Called from paint() (AWT) to repair damage
5224 if(!rectangleIsObscured(x, y, w, h)) {
5225 paintComponent(g);
5226 paintBorder(g);
5227 }
5228 paintChildren(g);
5229 }
5230 } finally {
5231 setFlag(ANCESTOR_USING_BUFFER, false);
5232 setFlag(IS_PAINTING_TILE, false);
5233 }
5234 }
5235
5236 /**
5237 * Returns whether or not the region of the specified component is
5238 * obscured by a sibling.
5239 *
5240 * @return NOT_OBSCURED if non of the siblings above the Component obscure
5241 * it, COMPLETELY_OBSCURED if one of the siblings completely
5242 * obscures the Component or PARTIALLY_OBSCURED if the Comonent is
5243 * only partially obscured.
5244 */
5245 private int getObscuredState(int compIndex, int x, int y, int width,
5246 int height) {
5247 int retValue = NOT_OBSCURED;
5248 Rectangle tmpRect = fetchRectangle();
5249
5250 for (int i = compIndex - 1 ; i >= 0 ; i--) {
5251 Component sibling = getComponent(i);
5252 if (!sibling.isVisible()) {
5253 continue;
5254 }
5255 Rectangle siblingRect;
5256 boolean opaque;
5257 if (sibling instanceof JComponent) {
5258 opaque = sibling.isOpaque();
5259 if (!opaque) {
5260 if (retValue == PARTIALLY_OBSCURED) {
5261 continue;
5262 }
5263 }
5264 }
5265 else {
5266 opaque = true;
5267 }
5268 siblingRect = sibling.getBounds(tmpRect);
5269 if (opaque && x >= siblingRect.x && (x + width) <=
5270 (siblingRect.x + siblingRect.width) &&
5271 y >= siblingRect.y && (y + height) <=
5272 (siblingRect.y + siblingRect.height)) {
5273 recycleRectangle(tmpRect);
5274 return COMPLETELY_OBSCURED;
5275 }
5276 else if (retValue == NOT_OBSCURED &&
5277 !((x + width <= siblingRect.x) ||
5278 (y + height <= siblingRect.y) ||
5279 (x >= siblingRect.x + siblingRect.width) ||
5280 (y >= siblingRect.y + siblingRect.height))) {
5281 retValue = PARTIALLY_OBSCURED;
5282 }
5283 }
5284 recycleRectangle(tmpRect);
5285 return retValue;
5286 }
5287
5288 /**
5289 * Returns true, which implies that before checking if a child should
5290 * be painted it is first check that the child is not obscured by another
5291 * sibling. This is only checked if <code>isOptimizedDrawingEnabled</code>
5292 * returns false.
5293 *
5294 * @return always returns true
5295 */
5296 boolean checkIfChildObscuredBySibling() {
5297 return true;
5298 }
5299
5300
5301 private void setFlag(int aFlag, boolean aValue) {
5302 if(aValue) {
5303 flags |= (1 << aFlag);
5304 } else {
5305 flags &= ~(1 << aFlag);
5306 }
5307 }
5308 private boolean getFlag(int aFlag) {
5309 int mask = (1 << aFlag);
5310 return ((flags & mask) == mask);
5311 }
5312 // These functions must be static so that they can be called from
5313 // subclasses inside the package, but whose inheritance hierarhcy includes
5314 // classes outside of the package below JComponent (e.g., JTextArea).
5315 static void setWriteObjCounter(JComponent comp, byte count) {
5316 comp.flags = (comp.flags & ~(0xFF << WRITE_OBJ_COUNTER_FIRST)) |
5317 (count << WRITE_OBJ_COUNTER_FIRST);
5318 }
5319 static byte getWriteObjCounter(JComponent comp) {
5320 return (byte)((comp.flags >> WRITE_OBJ_COUNTER_FIRST) & 0xFF);
5321 }
5322
5323 /** Buffering **/
5324
5325 /**
5326 * Sets whether this component should use a buffer to paint.
5327 * If set to true, all the drawing from this component will be done
5328 * in an offscreen painting buffer. The offscreen painting buffer will
5329 * the be copied onto the screen.
5330 * If a <code>Component</code> is buffered and one of its ancestor
5331 * is also buffered, the ancestor buffer will be used.
5332 *
5333 * @param aFlag if true, set this component to be double buffered
5334 */
5335 public void setDoubleBuffered(boolean aFlag) {
5336 setFlag(IS_DOUBLE_BUFFERED,aFlag);
5337 }
5338
5339 /**
5340 * Returns whether this component should use a buffer to paint.
5341 *
5342 * @return true if this component is double buffered, otherwise false
5343 */
5344 public boolean isDoubleBuffered() {
5345 return getFlag(IS_DOUBLE_BUFFERED);
5346 }
5347
5348 /**
5349 * Returns the <code>JRootPane</code> ancestor for this component.
5350 *
5351 * @return the <code>JRootPane</code> that contains this component,
5352 * or <code>null</code> if no <code>JRootPane</code> is found
5353 */
5354 public JRootPane getRootPane() {
5355 return SwingUtilities.getRootPane(this);
5356 }
5357
5358
5359 /** Serialization **/
5360
5361 /**
5362 * This is called from Component by way of reflection. Do NOT change
5363 * the name unless you change the code in Component as well.
5364 */
5365 void compWriteObjectNotify() {
5366 byte count = JComponent.getWriteObjCounter(this);
5367 JComponent.setWriteObjCounter(this, (byte)(count + 1));
5368 if (count != 0) {
5369 return;
5370 }
5371
5372 uninstallUIAndProperties();
5373
5374 /* JTableHeader is in a separate package, which prevents it from
5375 * being able to override this package-private method the way the
5376 * other components can. We don't want to make this method protected
5377 * because it would introduce public-api for a less-than-desirable
5378 * serialization scheme, so we compromise with this 'instanceof' hack
5379 * for now.
5380 */
5381 if (getToolTipText() != null ||
5382 this instanceof javax.swing.table.JTableHeader) {
5383 ToolTipManager.sharedInstance().unregisterComponent(JComponent.this);
5384 }
5385 }
5386
5387 /**
5388 * This object is the <code>ObjectInputStream</code> callback
5389 * that's called after a complete graph of objects (including at least
5390 * one <code>JComponent</code>) has been read.
5391 * It sets the UI property of each Swing component
5392 * that was read to the current default with <code>updateUI</code>.
5393 * <p>
5394 * As each component is read in we keep track of the current set of
5395 * root components here, in the roots vector. Note that there's only one
5396 * <code>ReadObjectCallback</code> per <code>ObjectInputStream</code>,
5397 * they're stored in the static <code>readObjectCallbacks</code>
5398 * hashtable.
5399 *
5400 * @see java.io.ObjectInputStream#registerValidation
5401 * @see SwingUtilities#updateComponentTreeUI
5402 */
5403 private class ReadObjectCallback implements ObjectInputValidation
5404 {
5405 private final Vector<JComponent> roots = new Vector<JComponent>(1);
5406 private final ObjectInputStream inputStream;
5407
5408 ReadObjectCallback(ObjectInputStream s) throws Exception {
5409 inputStream = s;
5410 s.registerValidation(this, 0);
5411 }
5412
5413 /**
5414 * This is the method that's called after the entire graph
5415 * of objects has been read in. It initializes
5416 * the UI property of all of the copmonents with
5417 * <code>SwingUtilities.updateComponentTreeUI</code>.
5418 */
5419 public void validateObject() throws InvalidObjectException {
5420 try {
5421 for (JComponent root : roots) {
5422 SwingUtilities.updateComponentTreeUI(root);
5423 }
5424 }
5425 finally {
5426 readObjectCallbacks.remove(inputStream);
5427 }
5428 }
5429
5430 /**
5431 * If <code>c</code> isn't a descendant of a component we've already
5432 * seen, then add it to the roots <code>Vector</code>.
5433 *
5434 * @param c the <code>JComponent</code> to add
5435 */
5436 private void registerComponent(JComponent c)
5437 {
5438 /* If the Component c is a descendant of one of the
5439 * existing roots (or it IS an existing root), we're done.
5440 */
5441 for (JComponent root : roots) {
5442 for(Component p = c; p != null; p = p.getParent()) {
5443 if (p == root) {
5444 return;
5445 }
5446 }
5447 }
5448
5449 /* Otherwise: if Component c is an ancestor of any of the
5450 * existing roots then remove them and add c (the "new root")
5451 * to the roots vector.
5452 */
5453 for(int i = 0; i < roots.size(); i++) {
5454 JComponent root = roots.elementAt(i);
5455 for(Component p = root.getParent(); p != null; p = p.getParent()) {
5456 if (p == c) {
5457 roots.removeElementAt(i--); // !!
5458 break;
5459 }
5460 }
5461 }
5462
5463 roots.addElement(c);
5464 }
5465 }
5466
5467
5468 /**
5469 * We use the <code>ObjectInputStream</code> "registerValidation"
5470 * callback to update the UI for the entire tree of components
5471 * after they've all been read in.
5472 *
5473 * @param s the <code>ObjectInputStream</code> from which to read
5474 */
5475 private void readObject(ObjectInputStream s)
5476 throws IOException, ClassNotFoundException
5477 {
5478 s.defaultReadObject();
5479
5480 /* If there's no ReadObjectCallback for this stream yet, that is, if
5481 * this is the first call to JComponent.readObject() for this
5482 * graph of objects, then create a callback and stash it
5483 * in the readObjectCallbacks table. Note that the ReadObjectCallback
5484 * constructor takes care of calling s.registerValidation().
5485 */
5486 ReadObjectCallback cb = readObjectCallbacks.get(s);
5487 if (cb == null) {
5488 try {
5489 readObjectCallbacks.put(s, cb = new ReadObjectCallback(s));
5490 }
5491 catch (Exception e) {
5492 throw new IOException(e.toString());
5493 }
5494 }
5495 cb.registerComponent(this);
5496
5497 // Read back the client properties.
5498 int cpCount = s.readInt();
5499 if (cpCount > 0) {
5500 clientProperties = new ArrayTable();
5501 for (int counter = 0; counter < cpCount; counter++) {
5502 clientProperties.put(s.readObject(),
5503 s.readObject());
5504 }
5505 }
5506 if (getToolTipText() != null) {
5507 ToolTipManager.sharedInstance().registerComponent(this);
5508 }
5509 setWriteObjCounter(this, (byte)0);
5510 }
5511
5512
5513 /**
5514 * Before writing a <code>JComponent</code> to an
5515 * <code>ObjectOutputStream</code> we temporarily uninstall its UI.
5516 * This is tricky to do because we want to uninstall
5517 * the UI before any of the <code>JComponent</code>'s children
5518 * (or its <code>LayoutManager</code> etc.) are written,
5519 * and we don't want to restore the UI until the most derived
5520 * <code>JComponent</code> subclass has been been stored.
5521 *
5522 * @param s the <code>ObjectOutputStream</code> in which to write
5523 */
5524 private void writeObject(ObjectOutputStream s) throws IOException {
5525 s.defaultWriteObject();
5526 if (getUIClassID().equals(uiClassID)) {
5527 byte count = JComponent.getWriteObjCounter(this);
5528 JComponent.setWriteObjCounter(this, --count);
5529 if (count == 0 && ui != null) {
5530 ui.installUI(this);
5531 }
5532 }
5533 ArrayTable.writeArrayTable(s, clientProperties);
5534 }
5535
5536
5537 /**
5538 * Returns a string representation of this <code>JComponent</code>.
5539 * This method
5540 * is intended to be used only for debugging purposes, and the
5541 * content and format of the returned string may vary between
5542 * implementations. The returned string may be empty but may not
5543 * be <code>null</code>.
5544 *
5545 * @return a string representation of this <code>JComponent</code>
5546 */
5547 protected String paramString() {
5548 String preferredSizeString = (isPreferredSizeSet() ?
5549 getPreferredSize().toString() : "");
5550 String minimumSizeString = (isMinimumSizeSet() ?
5551 getMinimumSize().toString() : "");
5552 String maximumSizeString = (isMaximumSizeSet() ?
5553 getMaximumSize().toString() : "");
5554 String borderString = (border == null ? ""
5555 : (border == this ? "this" : border.toString()));
5556
5557 return super.paramString() +
5558 ",alignmentX=" + alignmentX +
5559 ",alignmentY=" + alignmentY +
5560 ",border=" + borderString +
5561 ",flags=" + flags + // should beef this up a bit
5562 ",maximumSize=" + maximumSizeString +
5563 ",minimumSize=" + minimumSizeString +
5564 ",preferredSize=" + preferredSizeString;
5565 }
5566
5567 }